From 1a085d11cef8451490e52a2d554b1d1bdc3e4234 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Wed, 15 Feb 2023 19:12:01 +0100 Subject: [PATCH 01/45] Modify findTransitiveTransfer to call the pathfinder service --- .env.example | 1 + README.md | 1 + src/index.js | 4 ++ src/token.js | 131 ++++++++++++++++++++++++------------------- src/utils.js | 30 ++++++++++ test/helpers/core.js | 1 + test/token.test.js | 44 +++++++-------- 7 files changed, 131 insertions(+), 81 deletions(-) diff --git a/.env.example b/.env.example index 73dbec74..c691059b 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,7 @@ RPC_URL=http://localhost:8545 # Service Endpoints API_SERVICE_ENDPOINT=http://api.circles.local GRAPH_NODE_ENDPOINT=http://graph.circles.local +PATHFINDER_SERVICE_ENDPOINT=http://pathfinder.circles.local RELAY_SERVICE_ENDPOINT=http://relay.circles.local # Database Endpoints diff --git a/README.md b/README.md index a08d9183..b368d51c 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ const core = new CirclesCore(web3, { proxyFactoryAddress: '0x9b1f7F645351AF3631a656421eD2e40f2802E6c0', safeMasterAddress: '0x59d3631c86BbE35EF041872d502F218A39FBa150', apiServiceEndpoint: 'http://api.circles.local', + pathfinderServiceEndpoint: 'http://pathfinder.circles.local' graphNodeEndpoint: 'http://graph.circles.local', databaseSource: 'graph', relayServiceEndpoint: 'http://relay.circles.local', diff --git a/src/index.js b/src/index.js index 77f0ccc2..725384ed 100644 --- a/src/index.js +++ b/src/index.js @@ -25,6 +25,7 @@ export default class CirclesCore { * @param {Web3} web3 - instance of Web3 * @param {Object} options - global core options * @param {string} options.apiServiceEndpoint - URL of the username resolver service + * @param {string} options.pathfinderServiceEndpoint - URL of the pathfinder service * @param {string} options.databaseSource - database source type * @param {string} options.fallbackHandlerAddress - address of the fallback handler of the Safe contract * @param {string} options.graphNodeEndpoint - URL of the graph node @@ -67,6 +68,9 @@ export default class CirclesCore { apiServiceEndpoint: { type: 'string', }, + pathfinderServiceEndpoint: { + type: 'string', + }, relayServiceEndpoint: { type: 'string', }, diff --git a/src/token.js b/src/token.js index 97478d94..33110dbd 100644 --- a/src/token.js +++ b/src/token.js @@ -40,25 +40,24 @@ export async function findTransitiveTransfer(web3, utils, userOptions) { value: { type: web3.utils.isBN, }, - hops: { + maxTransfers: { type: 'number', - default: 3, + default: MAX_TRANSFER_STEPS, }, }); try { - const response = await utils.requestAPI({ - path: ['transfers'], + const response = await utils.requestPathfinderAPI({ method: 'POST', data: { from: options.from, to: options.to, value: options.value.toString(), - hops: options.hops.toString(), + maxTransfers: options.maxTransfers, }, }); - return response.data; + return response.result; } catch (error) { throw new TransferError(error.message, ErrorCodes.UNKNOWN_ERROR); } @@ -408,9 +407,9 @@ export default function createTokenModule(web3, contracts, utils) { type: 'string', default: '', }, - hops: { + maxTransfers: { type: 'number', - default: 3, + default: 40, }, }); @@ -423,64 +422,78 @@ export default function createTokenModule(web3, contracts, utils) { // Try first to send the transaction directly, this saves us the // roundtrip through the api - const sendLimit = await hub.methods - .checkSendLimit(options.from, options.from, options.to) + // Try first with the token of the 'to' address, + // then try with the token of the 'from' address. + const sendLimitTo = await hub.methods + .checkSendLimit(options.to, options.from, options.to) .call(); - if (web3.utils.toBN(sendLimit).gte(options.value)) { + if (web3.utils.toBN(sendLimitTo).gte(options.value)) { // Direct transfer is possible, fill in the required transaction data - transfer.tokenOwners.push(options.from); + transfer.tokenOwners.push(options.to); transfer.sources.push(options.from); transfer.destinations.push(options.to); transfer.values.push(options.value.toString()); } else { - // This seems to be a little bit more complicated ..., request API to - // find transitive transfer path - let response; - try { - response = await findTransitiveTransfer(web3, utils, options); - - if (web3.utils.toBN(response.maxFlowValue).lt(options.value)) { - throw new TransferError( - 'No possible transfer found', - ErrorCodes.TRANSFER_NOT_FOUND, - { - ...options, - response, - }, - ); - } - - if (response.transferSteps.length > MAX_TRANSFER_STEPS) { - throw new TransferError( - 'Too many transfer steps', - ErrorCodes.TOO_COMPLEX_TRANSFER, - { - ...options, - response, - }, - ); - } - - // Convert connections to contract argument format - response.transferSteps.forEach((transaction) => { - transfer.tokenOwners.push(transaction.tokenOwnerAddress); - transfer.sources.push(transaction.from); - transfer.destinations.push(transaction.to); - transfer.values.push(transaction.value); - }); - } catch (error) { - if (!error.code) { - throw new TransferError( - error.message, - ErrorCodes.INVALID_TRANSFER, - { - ...options, - response, - }, - ); - } else { - throw error; + const sendLimitFrom = await hub.methods + .checkSendLimit(options.from, options.from, options.to) + .call(); + if (web3.utils.toBN(sendLimitFrom).gte(options.value)) { + // Direct transfer is possible, fill in the required transaction data + transfer.tokenOwners.push(options.from); + transfer.sources.push(options.from); + transfer.destinations.push(options.to); + transfer.values.push(options.value.toString()); + } else { + + // This seems to be a little bit more complicated ..., request API to + // find transitive transfer path + let response; + try { + response = await findTransitiveTransfer(web3, utils, options); + + if (web3.utils.toBN(response.flow).lt(options.value)) { + throw new TransferError( + 'No possible transfer found', + ErrorCodes.TRANSFER_NOT_FOUND, + { + ...options, + response, + }, + ); + } + + if (response.transfers.length > MAX_TRANSFER_STEPS) { + throw new TransferError( + 'Too many transfer steps', + ErrorCodes.TOO_COMPLEX_TRANSFER, + { + ...options, + response, + }, + ); + } + + // Convert connections to contract argument format + response.transfers.forEach((transaction) => { + transfer.tokenOwners.push(transaction.token_owner); + transfer.sources.push(transaction.from); + transfer.destinations.push(transaction.to); + transfer.values.push(transaction.value); + }); + } catch (error) { + if (!error.code) { + throw new TransferError( + error.message, + ErrorCodes.INVALID_TRANSFER, + { + ...options, + response, + }, + ); + } else { + throw error; + } } } } diff --git a/src/utils.js b/src/utils.js index de26ed7e..0707c39b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -524,6 +524,7 @@ async function requestNonce(web3, endpoint, safeAddress) { export default function createUtilsModule(web3, contracts, globalOptions) { const { apiServiceEndpoint, + pathfinderServiceEndpoint, databaseSource, graphNodeEndpoint, relayServiceEndpoint, @@ -1098,6 +1099,35 @@ export default function createUtilsModule(web3, contracts, globalOptions) { }); }, + /** + * Make a request to the Circles server API. + * + * @namespace core.utils.requestPathfinderAPI + * + * @param {Object} userOptions - Pathfinder API query options + * @param {string} userOptions.method - HTTP method + * @param {Object} userOptions.data - Request body (JSON) + * + * @return {Object} - API response + */ + requestPathfinderAPI: async (userOptions) => { + const options = checkOptions(userOptions, { + method: { + type: 'string', + default: 'GET', + }, + data: { + type: 'object', + default: {}, + }, + }); + + return request(pathfinderServiceEndpoint, { + data: options.data, + method: options.method, + }); + }, + /** * Estimates the total gas fees for a relayer transaction. * diff --git a/test/helpers/core.js b/test/helpers/core.js index 67c3474c..fa23afff 100644 --- a/test/helpers/core.js +++ b/test/helpers/core.js @@ -8,6 +8,7 @@ export default function createCore() { fallbackHandlerAddress: process.env.SAFE_DEFAULT_CALLBACK_HANDLER, graphNodeEndpoint: process.env.GRAPH_NODE_ENDPOINT, hubAddress: process.env.HUB_ADDRESS, + pathfinderServiceEndpoint: process.env.PATHFINDER_SERVICE_ENDPOINT, proxyFactoryAddress: process.env.PROXY_FACTORY_ADDRESS, relayServiceEndpoint: process.env.RELAY_SERVICE_ENDPOINT, safeMasterAddress: process.env.SAFE_ADDRESS, diff --git a/test/token.test.js b/test/token.test.js index 45e81849..fbcaf873 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -168,20 +168,20 @@ describe('Token', () => { to: safeAddresses[4], value, }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + expect(result.transfers.length).toBe(2); + expect(result.transfers[0].from).toBe(safeAddresses[0]); + expect(result.transfers[0].to).toBe(safeAddresses[3]); + expect(result.transfers[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transfers[0].token_owner).toBe(safeAddresses[0]); + expect(result.transfers[1].from).toBe(safeAddresses[3]); + expect(result.transfers[1].to).toBe(safeAddresses[4]); + expect(result.transfers[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transfers[1].token_owner).toBe(safeAddresses[3]); // The `pathfinder` stops searching for max flow as soon as it found a // successful solution, therefore it returns a lower max flow than it // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + expect(result.flow).toBe(core.utils.toFreckles(1)); }); it('should return max flow and possible path when using hops parameter', async () => { @@ -193,20 +193,20 @@ describe('Token', () => { value, hops: 2, }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + expect(result.transfers.length).toBe(2); + expect(result.transfers[0].from).toBe(safeAddresses[0]); + expect(result.transfers[0].to).toBe(safeAddresses[3]); + expect(result.transfers[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transfers[0].token_owner).toBe(safeAddresses[0]); + expect(result.transfers[1].from).toBe(safeAddresses[3]); + expect(result.transfers[1].to).toBe(safeAddresses[4]); + expect(result.transfers[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transfers[1].token_owner).toBe(safeAddresses[3]); // The `pathfinder` stops searching for max flow as soon as it found a // successful solution, therefore it returns a lower max flow than it // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + expect(result.flow).toBe(core.utils.toFreckles(1)); }); it('should return 0 max flow and no path when using too low hops parameter', async () => { @@ -218,12 +218,12 @@ describe('Token', () => { value, hops: 1, }); - expect(result.transferSteps.length).toBe(0); + expect(result.transfers.length).toBe(0); // The `pathfinder` stops searching for max flow as soon as it found a // successful solution, therefore it returns a lower max flow than it // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); + expect(result.flow).toBe(core.utils.toFreckles(0)); }); }); From 0e7967c748565757bd53c46e8fffd70c5053a843 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Fri, 17 Feb 2023 00:15:25 +0100 Subject: [PATCH 02/45] enable to use both pathfinders --- src/token.js | 122 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 16 deletions(-) diff --git a/src/token.js b/src/token.js index 33110dbd..5365580b 100644 --- a/src/token.js +++ b/src/token.js @@ -13,9 +13,25 @@ import { getVersion } from '~/safe'; */ const MAX_TRANSFER_STEPS = 52; +async function requestTransferSteps( + web3, + utils, + userOptions, + pathfinderType = 'server', +) { + if (pathfinderType == 'cli') { + // call cli pathfinders + findTransitiveTransfer(web3, utils, userOptions); + } else if (pathfinderType == 'server') { + // call server + findTransitiveTransferServer(web3, utils, userOptions); + } +} + /** * Find maximumFlow and transfer steps through a trust graph from someone to - * someone else to transitively send an amount of Circles. + * someone else to transitively send an amount of Circles using the binary + * version of pathfinder2 * * @access private * @@ -30,6 +46,58 @@ const MAX_TRANSFER_STEPS = 52; * @return {Object[]} - transaction steps */ export async function findTransitiveTransfer(web3, utils, userOptions) { + const options = checkOptions(userOptions, { + from: { + type: web3.utils.checkAddressChecksum, + }, + to: { + type: web3.utils.checkAddressChecksum, + }, + value: { + type: web3.utils.isBN, + }, + hops: { + type: 'number', + default: 3, + }, + }); + + try { + const response = await utils.requestAPI({ + path: ['transfers'], + method: 'POST', + data: { + from: options.from, + to: options.to, + value: options.value.toString(), + hops: options.hops.toString(), + }, + }); + + return response.data; + } catch (error) { + throw new TransferError(error.message, ErrorCodes.UNKNOWN_ERROR); + } +} + +/** + * Find maximumFlow and transfer steps through a trust graph from someone to + * someone else to transitively send an amount of Circles using the server + * version of pathfinder2 + * + * @access private + * + * @param {Web3} web3 - Web3 instance + * @param {Object} utils - core utils + * @param {Object} userOptions - search arguments + * @param {string} userOptions.from - sender Safe address + * @param {string} userOptions.to - receiver Safe address + * @param {BN} userOptions.value - value of Circles tokens + * @param {number} userOptions.hops - maximum number of trust hops away from them sending user inside the trust network for finding transaction steps + * + * @return {Object[]} - transaction steps + */ +export async function findTransitiveTransferServer(web3, utils, userOptions) { const options = checkOptions(userOptions, { from: { type: web3.utils.checkAddressChecksum, @@ -387,10 +455,11 @@ export default function createTokenModule(web3, contracts, utils) { * @param {BN} userOptions.value - value * @param {string} userOptions.paymentNote - optional payment note stored in API * @param {number} userOptions.hops - maximum number of trust hops away from them sending user inside the trust network for finding transaction steps + * @param {string} pathfinderType - "cli" or "server" * * @return {string} - transaction hash */ - transfer: async (account, userOptions) => { + transfer: async (account, userOptions, pathfinderType = 'server') => { checkAccount(web3, account); const options = checkOptions(userOptions, { @@ -436,8 +505,8 @@ export default function createTokenModule(web3, contracts, utils) { transfer.values.push(options.value.toString()); } else { const sendLimitFrom = await hub.methods - .checkSendLimit(options.from, options.from, options.to) - .call(); + .checkSendLimit(options.from, options.from, options.to) + .call(); if (web3.utils.toBN(sendLimitFrom).gte(options.value)) { // Direct transfer is possible, fill in the required transaction data transfer.tokenOwners.push(options.from); @@ -445,14 +514,26 @@ export default function createTokenModule(web3, contracts, utils) { transfer.destinations.push(options.to); transfer.values.push(options.value.toString()); } else { - // This seems to be a little bit more complicated ..., request API to // find transitive transfer path let response; try { - response = await findTransitiveTransfer(web3, utils, options); - - if (web3.utils.toBN(response.flow).lt(options.value)) { + response = await requestTransferSteps( + web3, + utils, + options, + pathfinderType, + ); + let maxflow; + let totalTransfers; + if (pathfinderType == 'cli') { + maxflow == response.maxFlowValue; + totalTransfers == response.transferSteps; + } else if (pathfinderType == 'server') { + maxflow == response.flow; + totalTransfers == response.transfers; + } + if (web3.utils.toBN(maxflow).lt(options.value)) { throw new TransferError( 'No possible transfer found', ErrorCodes.TRANSFER_NOT_FOUND, @@ -463,7 +544,7 @@ export default function createTokenModule(web3, contracts, utils) { ); } - if (response.transfers.length > MAX_TRANSFER_STEPS) { + if (response.totalTransfers.length > MAX_TRANSFER_STEPS) { throw new TransferError( 'Too many transfer steps', ErrorCodes.TOO_COMPLEX_TRANSFER, @@ -474,13 +555,22 @@ export default function createTokenModule(web3, contracts, utils) { ); } - // Convert connections to contract argument format - response.transfers.forEach((transaction) => { - transfer.tokenOwners.push(transaction.token_owner); - transfer.sources.push(transaction.from); - transfer.destinations.push(transaction.to); - transfer.values.push(transaction.value); - }); + // Convert connections to contract argument format depending on the pathfinder used + if (pathfinderType == 'cli') { + response.transfers.forEach((transaction) => { + transfer.tokenOwners.push(transaction.tokenOwnerAddress); + transfer.sources.push(transaction.from); + transfer.destinations.push(transaction.to); + transfer.values.push(transaction.value); + }); + } else if (pathfinderType == 'server') { + response.transfers.forEach((transaction) => { + transfer.tokenOwners.push(transaction.token_owner); + transfer.sources.push(transaction.from); + transfer.destinations.push(transaction.to); + transfer.values.push(transaction.value); + }); + } } catch (error) { if (!error.code) { throw new TransferError( From a0e72fb961e4230cb88cba447ed0395f1beda2e1 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Fri, 17 Feb 2023 00:59:01 +0100 Subject: [PATCH 03/45] add variable for pathfinder type --- .env.example | 3 +++ src/token.js | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index c691059b..75c048f3 100644 --- a/.env.example +++ b/.env.example @@ -10,6 +10,9 @@ RELAY_SERVICE_ENDPOINT=http://relay.circles.local # Database Endpoints DATABASE_SOURCE=graph +# Pathfinder Type "cli" or "server" +PATHFINDER_TYPE="server" + # Smart Contract addresses of 1.3.0 version HUB_ADDRESS=0xCfEB869F69431e42cdB54A4F4f105C19C080A601 PROXY_FACTORY_ADDRESS=0x9b1f7F645351AF3631a656421eD2e40f2802E6c0 diff --git a/src/token.js b/src/token.js index 5365580b..7e840af3 100644 --- a/src/token.js +++ b/src/token.js @@ -190,12 +190,18 @@ export async function updateTransitiveTransfer(web3, utils, userOptions) { * @param {Web3} web3 - Web3 instance * @param {Object} contracts - common contract instances * @param {Object} utils - utils module instance + * @param {Object} globalOptions - global core options * * @return {Object} - token module instance */ -export default function createTokenModule(web3, contracts, utils) { +export default function createTokenModule( + web3, + contracts, + utils, + globalOptions, +) { const { hub } = contracts; - + const { pathfinderType } = globalOptions; return { /** * Returns true if there are enough balance on this Safe address to deploy @@ -416,11 +422,37 @@ export default function createTokenModule(web3, contracts, utils) { * * @return {Object} - maximum possible Circles value and transactions path */ + // findTransitiveTransfer(web3, utils, userOptions) findTransitiveTransfer: async (account, userOptions) => { checkAccount(web3, account); return await findTransitiveTransfer(web3, utils, userOptions); }, + /** + * Find Transitive Transfer Steps using either the cli or the server version + * of the pathfinder2 + * + * @namespace core.token.requestTransferSteps + * + * @param {Object} account - web3 account instance + * @param {Object} userOptions - search arguments + * @param {string} userOptions.from - sender Safe address + * @param {string} userOptions.to - receiver Safe address + * @param {BN} userOptions.value - value for transactions path + * @param {string} pathfinderType - "cli" or "server" + * + * @return {Object} - maximum possible Circles value and transactions path + */ + requestTransferSteps: async (account, userOptions) => { + checkAccount(web3, account); + return await requestTransferSteps( + web3, + utils, + userOptions, + pathfinderType, + ); + }, + /** * Update the transitive transfer steps from someone to someone for * an amount of Circles. From 5ce770c3da6c9ae7402f43c8f43f3db08eb6dbec Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Fri, 17 Feb 2023 01:00:41 +0100 Subject: [PATCH 04/45] update token to return steps regardless of which pathfinder it uses --- test/token.test.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/token.test.js b/test/token.test.js index fbcaf873..aa8b1a82 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -163,11 +163,15 @@ describe('Token', () => { it('should return max flow and possible path', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.findTransitiveTransfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - }); + const result = await core.token.requestTransferSteps( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value, + }, + 'server', + ); expect(result.transfers.length).toBe(2); expect(result.transfers[0].from).toBe(safeAddresses[0]); expect(result.transfers[0].to).toBe(safeAddresses[3]); From a5392bcca4a95fca00e0cb77019eb27151d82d82 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Fri, 17 Feb 2023 01:02:10 +0100 Subject: [PATCH 05/45] add pathfinderType --- src/index.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 725384ed..9c9f67e7 100644 --- a/src/index.js +++ b/src/index.js @@ -26,6 +26,7 @@ export default class CirclesCore { * @param {Object} options - global core options * @param {string} options.apiServiceEndpoint - URL of the username resolver service * @param {string} options.pathfinderServiceEndpoint - URL of the pathfinder service + * @param {string} options.pathfinderType - Type of pathfinder used to get transfer steps ("cli" or "server") * @param {string} options.databaseSource - database source type * @param {string} options.fallbackHandlerAddress - address of the fallback handler of the Safe contract * @param {string} options.graphNodeEndpoint - URL of the graph node @@ -77,6 +78,10 @@ export default class CirclesCore { subgraphName: { type: 'string', }, + pathfinderType: { + type: 'string', + default: 'server', + }, }); // Expose error classes and constants @@ -114,7 +119,12 @@ export default class CirclesCore { this.options, ); /** @type {Object} - token module */ - this.token = createTokenModule(web3, this.contracts, this.utils); + this.token = createTokenModule( + web3, + this.contracts, + this.utils, + this.options, + ); /** @type {Object} - trust module */ this.trust = createTrustModule(web3, this.contracts, this.utils); /** @type {Object} - user module */ From 61010b6e8f04b06168d2c729e67f5e96fad7ccc0 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Mon, 20 Feb 2023 09:49:22 +0100 Subject: [PATCH 06/45] Fix typo --- .env.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 75c048f3..ee13d1c4 100644 --- a/.env.example +++ b/.env.example @@ -10,8 +10,8 @@ RELAY_SERVICE_ENDPOINT=http://relay.circles.local # Database Endpoints DATABASE_SOURCE=graph -# Pathfinder Type "cli" or "server" -PATHFINDER_TYPE="server" +# Pathfinder Type 'cli' or 'server' +PATHFINDER_TYPE=server # Smart Contract addresses of 1.3.0 version HUB_ADDRESS=0xCfEB869F69431e42cdB54A4F4f105C19C080A601 From ba4109fa8ad40902f8dffb6da7f657155ee34958 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Mon, 20 Feb 2023 09:56:10 +0100 Subject: [PATCH 07/45] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b368d51c..151993cd 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ const core = new CirclesCore(web3, { safeMasterAddress: '0x59d3631c86BbE35EF041872d502F218A39FBa150', apiServiceEndpoint: 'http://api.circles.local', pathfinderServiceEndpoint: 'http://pathfinder.circles.local' + pathfinderType: 'server', graphNodeEndpoint: 'http://graph.circles.local', databaseSource: 'graph', relayServiceEndpoint: 'http://relay.circles.local', From 8bc589e4ddbb5d42c6691f5f492f3fcaa982eebb Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Thu, 23 Feb 2023 01:47:12 +0100 Subject: [PATCH 08/45] include call to different pathfinder --- .github/workflows/tests.yml | 2 +- src/token.js | 117 ++++++++++++--------- src/utils.js | 3 +- test/token.test.js | 196 +++++++++++++++++++++++++----------- 4 files changed, 209 insertions(+), 109 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ade1d727..d42951fa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -49,7 +49,7 @@ jobs: uses: actions/checkout@v3 with: repository: CirclesUBI/circles-docker.git - ref: main + ref: pathfinder2-dev-env path: circles-docker - name: Setup docker repo diff --git a/src/token.js b/src/token.js index 7e840af3..de90cd19 100644 --- a/src/token.js +++ b/src/token.js @@ -19,13 +19,15 @@ async function requestTransferSteps( userOptions, pathfinderType = 'server', ) { + let result; if (pathfinderType == 'cli') { // call cli pathfinders - findTransitiveTransfer(web3, utils, userOptions); + result = await findTransitiveTransfer(web3, utils, userOptions); } else if (pathfinderType == 'server') { // call server - findTransitiveTransferServer(web3, utils, userOptions); + result = await findTransitiveTransferServer(web3, utils, userOptions); } + return result; } /** @@ -61,7 +63,6 @@ export async function findTransitiveTransfer(web3, utils, userOptions) { default: 3, }, }); - try { const response = await utils.requestAPI({ path: ['transfers'], @@ -73,7 +74,6 @@ export async function findTransitiveTransfer(web3, utils, userOptions) { hops: options.hops.toString(), }, }); - return response.data; } catch (error) { throw new TransferError(error.message, ErrorCodes.UNKNOWN_ERROR); @@ -112,19 +112,27 @@ export async function findTransitiveTransferServer(web3, utils, userOptions) { type: 'number', default: MAX_TRANSFER_STEPS, }, + pathfinderMethod: { + type: 'string', + default: 'compute_transfer', + }, }); try { const response = await utils.requestPathfinderAPI({ method: 'POST', data: { - from: options.from, - to: options.to, - value: options.value.toString(), - maxTransfers: options.maxTransfers, + id: Date.now(), + method: options.pathfinderMethod, + params: { + from: options.from, + to: options.to, + value: options.value.toString(), + max_transfers: options.maxTransfers, + }, }, + isTrailingSlash: false, }); - return response.result; } catch (error) { throw new TransferError(error.message, ErrorCodes.UNKNOWN_ERROR); @@ -198,10 +206,10 @@ export default function createTokenModule( web3, contracts, utils, - globalOptions, + // globalOptions, ) { const { hub } = contracts; - const { pathfinderType } = globalOptions; + // const { pathfinderType } = globalOptions; return { /** * Returns true if there are enough balance on this Safe address to deploy @@ -443,7 +451,7 @@ export default function createTokenModule( * * @return {Object} - maximum possible Circles value and transactions path */ - requestTransferSteps: async (account, userOptions) => { + requestTransferSteps: async (account, userOptions, pathfinderType) => { checkAccount(web3, account); return await requestTransferSteps( web3, @@ -493,26 +501,53 @@ export default function createTokenModule( */ transfer: async (account, userOptions, pathfinderType = 'server') => { checkAccount(web3, account); - - const options = checkOptions(userOptions, { - from: { - type: web3.utils.checkAddressChecksum, - }, - to: { - type: web3.utils.checkAddressChecksum, - }, - value: { - type: web3.utils.isBN, - }, - paymentNote: { - type: 'string', - default: '', - }, - maxTransfers: { - type: 'number', - default: 40, - }, - }); + let fieldObject; + if (pathfinderType == 'cli') { + fieldObject = { + from: { + type: web3.utils.checkAddressChecksum, + }, + to: { + type: web3.utils.checkAddressChecksum, + }, + value: { + type: web3.utils.isBN, + }, + paymentNote: { + type: 'string', + default: '', + }, + hops: { + type: 'number', + default: 3, + }, + }; + } else { + fieldObject = { + from: { + type: web3.utils.checkAddressChecksum, + }, + to: { + type: web3.utils.checkAddressChecksum, + }, + value: { + type: web3.utils.isBN, + }, + paymentNote: { + type: 'string', + default: '', + }, + maxTransfers: { + type: 'number', + default: 40, + }, + pathfinderMethod: { + type: 'string', + default: 'compute_transfer', + }, + }; + } + const options = checkOptions(userOptions, fieldObject); const transfer = { tokenOwners: [], @@ -556,16 +591,7 @@ export default function createTokenModule( options, pathfinderType, ); - let maxflow; - let totalTransfers; - if (pathfinderType == 'cli') { - maxflow == response.maxFlowValue; - totalTransfers == response.transferSteps; - } else if (pathfinderType == 'server') { - maxflow == response.flow; - totalTransfers == response.transfers; - } - if (web3.utils.toBN(maxflow).lt(options.value)) { + if (web3.utils.toBN(response.maxFlowValue).lt(options.value)) { throw new TransferError( 'No possible transfer found', ErrorCodes.TRANSFER_NOT_FOUND, @@ -576,7 +602,7 @@ export default function createTokenModule( ); } - if (response.totalTransfers.length > MAX_TRANSFER_STEPS) { + if (response.transferSteps.length > MAX_TRANSFER_STEPS) { throw new TransferError( 'Too many transfer steps', ErrorCodes.TOO_COMPLEX_TRANSFER, @@ -586,17 +612,16 @@ export default function createTokenModule( }, ); } - // Convert connections to contract argument format depending on the pathfinder used if (pathfinderType == 'cli') { - response.transfers.forEach((transaction) => { + response.transferSteps.forEach((transaction) => { transfer.tokenOwners.push(transaction.tokenOwnerAddress); transfer.sources.push(transaction.from); transfer.destinations.push(transaction.to); transfer.values.push(transaction.value); }); } else if (pathfinderType == 'server') { - response.transfers.forEach((transaction) => { + response.transferSteps.forEach((transaction) => { transfer.tokenOwners.push(transaction.token_owner); transfer.sources.push(transaction.from); transfer.destinations.push(transaction.to); diff --git a/src/utils.js b/src/utils.js index 0707c39b..7ec7fa6b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1121,10 +1121,11 @@ export default function createUtilsModule(web3, contracts, globalOptions) { default: {}, }, }); - return request(pathfinderServiceEndpoint, { data: options.data, method: options.method, + path: [], + isTrailingSlash: false, }); }, diff --git a/test/token.test.js b/test/token.test.js index aa8b1a82..32fa90fe 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -154,15 +154,81 @@ describe('Token', () => { describe('Find transitive transfer steps', () => { let safeAddresses; - beforeAll(async () => { const result = await deployTestNetwork(core, accounts); safeAddresses = result.safeAddresses; }); - - it('should return max flow and possible path', async () => { + it('should return max flow and possible path when using pathfinder binary.', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value, + }, + 'cli', + ); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + }); + it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value, + hops: 2, + }, + 'cli', + ); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + }); + it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value, + hops: 1, + }, + 'cli', + ); + expect(result.transferSteps.length).toBe(0); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); + }); + it('should return max flow and possible path when using pathfinder server', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps( accounts[0], { @@ -172,65 +238,65 @@ describe('Token', () => { }, 'server', ); - expect(result.transfers.length).toBe(2); - expect(result.transfers[0].from).toBe(safeAddresses[0]); - expect(result.transfers[0].to).toBe(safeAddresses[3]); - expect(result.transfers[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transfers[0].token_owner).toBe(safeAddresses[0]); - expect(result.transfers[1].from).toBe(safeAddresses[3]); - expect(result.transfers[1].to).toBe(safeAddresses[4]); - expect(result.transfers[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transfers[1].token_owner).toBe(safeAddresses[3]); - + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); // The `pathfinder` stops searching for max flow as soon as it found a // successful solution, therefore it returns a lower max flow than it // actually is (25). - expect(result.flow).toBe(core.utils.toFreckles(1)); + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); }); - - it('should return max flow and possible path when using hops parameter', async () => { + it('should return max flow and possible path when using max_transfers parameter in pathfinder server', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - - const result = await core.token.findTransitiveTransfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - hops: 2, - }); - expect(result.transfers.length).toBe(2); - expect(result.transfers[0].from).toBe(safeAddresses[0]); - expect(result.transfers[0].to).toBe(safeAddresses[3]); - expect(result.transfers[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transfers[0].token_owner).toBe(safeAddresses[0]); - expect(result.transfers[1].from).toBe(safeAddresses[3]); - expect(result.transfers[1].to).toBe(safeAddresses[4]); - expect(result.transfers[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transfers[1].token_owner).toBe(safeAddresses[3]); - + const result = await core.token.requestTransferSteps( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value, + maxTransfers: 2, + }, + 'server', + ); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); // The `pathfinder` stops searching for max flow as soon as it found a // successful solution, therefore it returns a lower max flow than it // actually is (25). - expect(result.flow).toBe(core.utils.toFreckles(1)); + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); }); - - it('should return 0 max flow and no path when using too low hops parameter', async () => { + it('should return 0 max flow and no path when using too low max_transfer parameter in pathfinder server', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - - const result = await core.token.findTransitiveTransfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - hops: 1, - }); - expect(result.transfers.length).toBe(0); - + const result = await core.token.requestTransferSteps( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value, + maxTransfers: 1, + }, + 'server', + ); + expect(result.transferSteps.length).toBe(0); // The `pathfinder` stops searching for max flow as soon as it found a // successful solution, therefore it returns a lower max flow than it // actually is (25). - expect(result.flow).toBe(core.utils.toFreckles(0)); + expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); }); }); - describe('Transitive Transactions', () => { let safeAddresses; let tokenAddresses; @@ -333,18 +399,18 @@ describe('Token', () => { ).rejects.toThrow(); }); - it('should fail to send Circles to someone transitively if hops are too few to find a path', async () => { + it('should fail to send Circles to someone transitively if maxTransfers value is too small to find a path', async () => { await expect( core.token.transfer(accounts[0], { from: safeAddresses[0], to: safeAddresses[4], value: web3.utils.toBN(core.utils.toFreckles(5)), - hops: 1, + maxTransfers: 1, }), ).rejects.toThrow(); }); - it('should fail sending Circles when data error', async () => { + it('should fail sending Circles when data error when using the pathfinder binary', async () => { // Update the edges.csv file simulating data error: // Direct path does not exist between safeAddress 0 and 4, // thus we create a false edge between safeAddress 0 and 4 @@ -360,11 +426,15 @@ describe('Token', () => { // Attempt to send an ammount which we know is higher // than the allowed by the blockchain data await expect( - core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - }), + core.token.transfer( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + }, + 'cli', + ), ).rejects.toThrow(); const updateResult = await core.token.updateTransferSteps(accounts[0], { @@ -376,11 +446,15 @@ describe('Token', () => { expect(updateResult.updated).toBe(true); // Only after updating the path, the transfer can succeed - const response = await core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - }); + const response = await core.token.transfer( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + }, + 'cli', + ); expect(web3.utils.isHexStrict(response)).toBe(true); }); From 5d1058bcb54272e2c01d49eb45f8683eaccef71b Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Thu, 23 Feb 2023 01:49:39 +0100 Subject: [PATCH 09/45] update .env.example --- .env.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index ee13d1c4..c7ae514d 100644 --- a/.env.example +++ b/.env.example @@ -4,14 +4,14 @@ RPC_URL=http://localhost:8545 # Service Endpoints API_SERVICE_ENDPOINT=http://api.circles.local GRAPH_NODE_ENDPOINT=http://graph.circles.local -PATHFINDER_SERVICE_ENDPOINT=http://pathfinder.circles.local +PATHFINDER_SERVICE_ENDPOINT=http://localhost:8081 RELAY_SERVICE_ENDPOINT=http://relay.circles.local # Database Endpoints DATABASE_SOURCE=graph # Pathfinder Type 'cli' or 'server' -PATHFINDER_TYPE=server +PATHFINDER_TYPE='server' # Smart Contract addresses of 1.3.0 version HUB_ADDRESS=0xCfEB869F69431e42cdB54A4F4f105C19C080A601 From 12fd89d4947e2772655a65fa55886e7370719077 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Thu, 23 Feb 2023 14:04:35 +0100 Subject: [PATCH 10/45] add pathfinder docker compose --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d42951fa..73f0e051 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,7 +58,7 @@ jobs: - name: Container setup via docker-compose working-directory: circles-docker - run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -p circles up --detach --remove-orphans --build + run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Download and migrate contracts working-directory: circles-docker @@ -70,7 +70,7 @@ jobs: - name: Try starting failed services working-directory: circles-docker - run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -p circles up --detach --remove-orphans --build + run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Install dependencies working-directory: circles-core From 972660ae48f5210e8d26548bbe87b56ef6d844e9 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 13:07:43 +0100 Subject: [PATCH 11/45] force build --- test/token.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/token.test.js b/test/token.test.js index 32fa90fe..a077867a 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -227,7 +227,7 @@ describe('Token', () => { // actually is (25). expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); }); - it('should return max flow and possible path when using pathfinder server', async () => { + it('should return max flow and possible path when using pathfinder server.', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); const result = await core.token.requestTransferSteps( accounts[0], From 85e94f533e04ddd7d4b378d118e87af39becdab7 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 13:19:57 +0100 Subject: [PATCH 12/45] update test workflows --- .github/workflows/tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 73f0e051..e0d8cb9a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -51,7 +51,9 @@ jobs: repository: CirclesUBI/circles-docker.git ref: pathfinder2-dev-env path: circles-docker - + - name: Delete Ganache docker + working-directory: circles-docker + run: docker stop circles-ganache; docker rm circles-ganache - name: Setup docker repo working-directory: circles-docker run: cp .env.example .env From 22bc9690c8a353ac044f8963dbe3bc505945b678 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 14:11:08 +0100 Subject: [PATCH 13/45] update test workflows --- .github/workflows/tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e0d8cb9a..73f0e051 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -51,9 +51,7 @@ jobs: repository: CirclesUBI/circles-docker.git ref: pathfinder2-dev-env path: circles-docker - - name: Delete Ganache docker - working-directory: circles-docker - run: docker stop circles-ganache; docker rm circles-ganache + - name: Setup docker repo working-directory: circles-docker run: cp .env.example .env From f808ab7252ac64dc699395e41144cc51376fe9e5 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 15:41:39 +0100 Subject: [PATCH 14/45] use docker compose v2 --- .github/workflows/tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 73f0e051..4e9f0b25 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest env: ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' - DOCKER_COMPOSE: docker-compose -f docker-compose.yml -f docker-compose.frontend.yml -p circles + DOCKER_COMPOSE: docker compose -f docker-compose.yml -f docker-compose.frontend.yml -p circles steps: - name: Add hosts to /etc/hosts @@ -58,7 +58,7 @@ jobs: - name: Container setup via docker-compose working-directory: circles-docker - run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Download and migrate contracts working-directory: circles-docker @@ -70,7 +70,7 @@ jobs: - name: Try starting failed services working-directory: circles-docker - run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Install dependencies working-directory: circles-core From cf8f074409eb751b2d542bdeb3b51a054488a8e3 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 16:33:37 +0100 Subject: [PATCH 15/45] force build --- test/token.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/token.test.js b/test/token.test.js index a077867a..bf679fef 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -222,6 +222,7 @@ describe('Token', () => { 'cli', ); expect(result.transferSteps.length).toBe(0); + // The `pathfinder` stops searching for max flow as soon as it found a // successful solution, therefore it returns a lower max flow than it // actually is (25). From 8ae2be7307a4f4dd951d0d7979929b0f88753dd6 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 17:54:42 +0100 Subject: [PATCH 16/45] removing temporally the cache --- .github/workflows/tests.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4e9f0b25..972e6acd 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,15 +35,15 @@ jobs: with: node-version: '${{ steps.nvmrc.outputs.NODE_VERSION }}' - - name: Cache Node.js modules - uses: actions/cache@v3 - with: - # npm cache files are stored in `~/.npm` on Linux/macOS. - path: ~/.npm - key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node- - ${{ runner.OS }}- + # - name: Cache Node.js modules + # uses: actions/cache@v3 + # with: + # # npm cache files are stored in `~/.npm` on Linux/macOS. + # path: ~/.npm + # key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} + # restore-keys: | + # ${{ runner.OS }}-node- + # ${{ runner.OS }}- - name: Get circles-docker repository and copy configs uses: actions/checkout@v3 From 110d08b460ab856f3e1cb96156083f531fe4701d Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 21:28:12 +0100 Subject: [PATCH 17/45] undo remove cache --- .github/workflows/tests.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 972e6acd..4e9f0b25 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -35,15 +35,15 @@ jobs: with: node-version: '${{ steps.nvmrc.outputs.NODE_VERSION }}' - # - name: Cache Node.js modules - # uses: actions/cache@v3 - # with: - # # npm cache files are stored in `~/.npm` on Linux/macOS. - # path: ~/.npm - # key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} - # restore-keys: | - # ${{ runner.OS }}-node- - # ${{ runner.OS }}- + - name: Cache Node.js modules + uses: actions/cache@v3 + with: + # npm cache files are stored in `~/.npm` on Linux/macOS. + path: ~/.npm + key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.OS }}-node- + ${{ runner.OS }}- - name: Get circles-docker repository and copy configs uses: actions/checkout@v3 From a731a249e822dc6f917fdfd25bc9e04c9acd3dd6 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 21:52:44 +0100 Subject: [PATCH 18/45] update test to include update .env --- .github/workflows/tests.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4e9f0b25..1346d1a9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,6 +63,10 @@ jobs: - name: Download and migrate contracts working-directory: circles-docker run: ./scripts/migrate-contracts.sh + + - name: Update .env file + working-directory: circles-docker + run: ./scripts/update_contract_addresses.sh - name: Create and deploy subgraph working-directory: circles-docker From f401508b461d1a6f32651929dcc815bb43440110 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Mon, 27 Feb 2023 23:05:26 +0100 Subject: [PATCH 19/45] force recreate docker after env file updated --- .github/workflows/tests.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1346d1a9..05e1119b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest env: ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true' - DOCKER_COMPOSE: docker compose -f docker-compose.yml -f docker-compose.frontend.yml -p circles + DOCKER_COMPOSE: docker-compose -f docker-compose.yml -f docker-compose.frontend.yml -p circles steps: - name: Add hosts to /etc/hosts @@ -58,7 +58,7 @@ jobs: - name: Container setup via docker-compose working-directory: circles-docker - run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Download and migrate contracts working-directory: circles-docker @@ -71,10 +71,13 @@ jobs: - name: Create and deploy subgraph working-directory: circles-docker run: ./scripts/deploy-subgraph.sh + - name: Try starting failed services + working-directory: circles-docker + run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up –force-recreate - name: Try starting failed services working-directory: circles-docker - run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Install dependencies working-directory: circles-core From 1be74da9291d5fff3e928ad4c8b64893c276f547 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Tue, 28 Feb 2023 15:07:28 +0100 Subject: [PATCH 20/45] force recreate --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 05e1119b..12ffa2df 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -73,7 +73,7 @@ jobs: run: ./scripts/deploy-subgraph.sh - name: Try starting failed services working-directory: circles-docker - run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up –force-recreate + run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up -–force-recreate - name: Try starting failed services working-directory: circles-docker From 676750409509877b3f5f5decdd22343adf32ebaa Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Wed, 1 Mar 2023 13:39:22 +0100 Subject: [PATCH 21/45] update workflow --- .github/workflows/tests.yml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 12ffa2df..95c2727d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,7 +58,7 @@ jobs: - name: Container setup via docker-compose working-directory: circles-docker - run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Download and migrate contracts working-directory: circles-docker @@ -71,13 +71,26 @@ jobs: - name: Create and deploy subgraph working-directory: circles-docker run: ./scripts/deploy-subgraph.sh + + # - name: Run indexer-db + # working-directory: circles-docker + # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up indexer-db + + # - name: Run indexer-db background + # working-directory: circles-docker + # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up -d indexer-db + + # - name: Run indexer-db-init + # working-directory: circles-docker + # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml run --rm indexer-db-init + - name: Try starting failed services working-directory: circles-docker - run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up -–force-recreate + run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Try starting failed services working-directory: circles-docker - run: docker-compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build - name: Install dependencies working-directory: circles-core From 7a390111cacf4d40f1329b744ab70daea1562ee1 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Wed, 1 Mar 2023 16:36:43 +0100 Subject: [PATCH 22/45] update workflow status --- .github/workflows/tests.yml | 41 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 95c2727d..0ea33421 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,41 +56,42 @@ jobs: working-directory: circles-docker run: cp .env.example .env - - name: Container setup via docker-compose + - name: Container setup via docker-compose without pathfinder working-directory: circles-docker - run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -p circles up --detach --remove-orphans --build - name: Download and migrate contracts working-directory: circles-docker run: ./scripts/migrate-contracts.sh - - name: Update .env file - working-directory: circles-docker - run: ./scripts/update_contract_addresses.sh + + # - name: Update .env file + # working-directory: circles-docker + # run: ./scripts/update_contract_addresses.sh - name: Create and deploy subgraph working-directory: circles-docker run: ./scripts/deploy-subgraph.sh - - # - name: Run indexer-db - # working-directory: circles-docker - # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up indexer-db - - # - name: Run indexer-db background - # working-directory: circles-docker - # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up -d indexer-db - - # - name: Run indexer-db-init - # working-directory: circles-docker - # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml run --rm indexer-db-init - + - name: Try starting failed services working-directory: circles-docker run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + + - name: Container setup via docker-compose for pathfinder + working-directory: circles-docker + run: docker compose -f docker-compose.pathfinder-pull.yml -p circles up --detach --build - - name: Try starting failed services + - name: Run indexer-db working-directory: circles-docker - run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up indexer-db + + - name: Run indexer-db background + working-directory: circles-docker + run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up -d indexer-db + + - name: Run indexer-db-init + working-directory: circles-docker + run: docker compose -p circles -f docker-compose.pathfinder-pull.yml run --rm indexer-db-init - name: Install dependencies working-directory: circles-core From 8c81da928f7502c0b9d2201cda3fc7381a25abed Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Wed, 1 Mar 2023 16:50:24 +0100 Subject: [PATCH 23/45] update workflow status --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0ea33421..5774ae47 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -75,7 +75,7 @@ jobs: - name: Try starting failed services working-directory: circles-docker - run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -f docker-compose.pathfinder-pull.yml -p circles up --detach --remove-orphans --build + run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -p circles up --detach --remove-orphans --build - name: Container setup via docker-compose for pathfinder working-directory: circles-docker From 9c2d7b4b35e45d9ec96fc74eaf528dd2cbb7421b Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Wed, 1 Mar 2023 16:56:06 +0100 Subject: [PATCH 24/45] update token test with server flag --- test/token.test.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/token.test.js b/test/token.test.js index bf679fef..2759cbb7 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -125,12 +125,16 @@ describe('Token', () => { // Send some Circles on that path and store payment note const value = new web3.utils.BN(core.utils.toFreckles(3)); paymentNote = 'Thank you for the fish'; - txHash = await core.token.transfer(accounts[0], { - from: sender.safeAddress, - to: receiver.safeAddress, - value, - paymentNote, - }); + txHash = await core.token.transfer( + accounts[0], + { + from: sender.safeAddress, + to: receiver.safeAddress, + value, + paymentNote, + }, + 'server', + ); expect(web3.utils.isHexStrict(txHash)).toBe(true); }); From 29bd41cc5547d3790078ce88539f19cbcb7c4403 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Wed, 1 Mar 2023 17:29:38 +0100 Subject: [PATCH 25/45] update workflow --- .github/workflows/tests.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5774ae47..14f08669 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -81,10 +81,6 @@ jobs: working-directory: circles-docker run: docker compose -f docker-compose.pathfinder-pull.yml -p circles up --detach --build - - name: Run indexer-db - working-directory: circles-docker - run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up indexer-db - - name: Run indexer-db background working-directory: circles-docker run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up -d indexer-db From 6b7fde13012f198d075d44890e68b457c437161b Mon Sep 17 00:00:00 2001 From: Elena San Miguel Date: Thu, 2 Mar 2023 12:17:31 +1000 Subject: [PATCH 26/45] Update .env.example --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index c7ae514d..0e68968a 100644 --- a/.env.example +++ b/.env.example @@ -11,7 +11,7 @@ RELAY_SERVICE_ENDPOINT=http://relay.circles.local DATABASE_SOURCE=graph # Pathfinder Type 'cli' or 'server' -PATHFINDER_TYPE='server' +PATHFINDER_TYPE=server # Smart Contract addresses of 1.3.0 version HUB_ADDRESS=0xCfEB869F69431e42cdB54A4F4f105C19C080A601 From b6551094cef7d5d4c5f8c28e93895617d53a806d Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Thu, 2 Mar 2023 04:03:22 +0100 Subject: [PATCH 27/45] update env file --- .env.example | 6 +++--- test/token.test.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index c7ae514d..db7e61b4 100644 --- a/.env.example +++ b/.env.example @@ -7,11 +7,11 @@ GRAPH_NODE_ENDPOINT=http://graph.circles.local PATHFINDER_SERVICE_ENDPOINT=http://localhost:8081 RELAY_SERVICE_ENDPOINT=http://relay.circles.local -# Database Endpoints +# Database Endpoint DATABASE_SOURCE=graph -# Pathfinder Type 'cli' or 'server' -PATHFINDER_TYPE='server' +# Pathfinder Type cli or server +PATHFINDER_TYPE=server # Smart Contract addresses of 1.3.0 version HUB_ADDRESS=0xCfEB869F69431e42cdB54A4F4f105C19C080A601 diff --git a/test/token.test.js b/test/token.test.js index 2759cbb7..0903fe26 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -133,7 +133,7 @@ describe('Token', () => { value, paymentNote, }, - 'server', + 'cli', ); expect(web3.utils.isHexStrict(txHash)).toBe(true); From c80b2875778691fdbedbffeb73dbe6e72948c352 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Wed, 8 Mar 2023 04:29:11 +0100 Subject: [PATCH 28/45] update token method --- .github/workflows/tests.yml | 12 ++-- src/token.js | 27 ++++--- test/helpers/core.js | 1 + test/token.test.js | 136 +++++++++++++----------------------- 4 files changed, 74 insertions(+), 102 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 14f08669..1491805c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -81,13 +81,13 @@ jobs: working-directory: circles-docker run: docker compose -f docker-compose.pathfinder-pull.yml -p circles up --detach --build - - name: Run indexer-db background - working-directory: circles-docker - run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up -d indexer-db + # - name: Run indexer-db background + # working-directory: circles-docker + # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up -d indexer-db - - name: Run indexer-db-init - working-directory: circles-docker - run: docker compose -p circles -f docker-compose.pathfinder-pull.yml run --rm indexer-db-init + # - name: Run indexer-db-init + # working-directory: circles-docker + # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml run --rm indexer-db-init - name: Install dependencies working-directory: circles-core diff --git a/src/token.js b/src/token.js index de90cd19..c2e98dff 100644 --- a/src/token.js +++ b/src/token.js @@ -13,12 +13,20 @@ import { getVersion } from '~/safe'; */ const MAX_TRANSFER_STEPS = 52; -async function requestTransferSteps( - web3, - utils, - userOptions, - pathfinderType = 'server', -) { +/** + * Find maximumFlow and transfer steps through a trust graph from someone to + * someone else to transitively send an amount of Circles using the binary + * version of pathfinder2 or the rpc server version + * + * @access private + * + * @param {Web3} web3 - Web3 instance + * @param {Object} utils - core utils + * @param {Object} userOptions - search arguments + * + * @return {Object[]} - transaction steps + */ +async function requestTransferSteps(web3, utils, userOptions, pathfinderType) { let result; if (pathfinderType == 'cli') { // call cli pathfinders @@ -206,10 +214,10 @@ export default function createTokenModule( web3, contracts, utils, - // globalOptions, + globalOptions, ) { const { hub } = contracts; - // const { pathfinderType } = globalOptions; + const { pathfinderType } = globalOptions; return { /** * Returns true if there are enough balance on this Safe address to deploy @@ -447,11 +455,10 @@ export default function createTokenModule( * @param {string} userOptions.from - sender Safe address * @param {string} userOptions.to - receiver Safe address * @param {BN} userOptions.value - value for transactions path - * @param {string} pathfinderType - "cli" or "server" * * @return {Object} - maximum possible Circles value and transactions path */ - requestTransferSteps: async (account, userOptions, pathfinderType) => { + requestTransferSteps: async (account, userOptions) => { checkAccount(web3, account); return await requestTransferSteps( web3, diff --git a/test/helpers/core.js b/test/helpers/core.js index fa23afff..a8d63bd7 100644 --- a/test/helpers/core.js +++ b/test/helpers/core.js @@ -9,6 +9,7 @@ export default function createCore() { graphNodeEndpoint: process.env.GRAPH_NODE_ENDPOINT, hubAddress: process.env.HUB_ADDRESS, pathfinderServiceEndpoint: process.env.PATHFINDER_SERVICE_ENDPOINT, + pathfinderType: process.env.PATHFINDER_TYPE, proxyFactoryAddress: process.env.PROXY_FACTORY_ADDRESS, relayServiceEndpoint: process.env.RELAY_SERVICE_ENDPOINT, safeMasterAddress: process.env.SAFE_ADDRESS, diff --git a/test/token.test.js b/test/token.test.js index 0903fe26..331b68c6 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -125,16 +125,12 @@ describe('Token', () => { // Send some Circles on that path and store payment note const value = new web3.utils.BN(core.utils.toFreckles(3)); paymentNote = 'Thank you for the fish'; - txHash = await core.token.transfer( - accounts[0], - { - from: sender.safeAddress, - to: receiver.safeAddress, - value, - paymentNote, - }, - 'cli', - ); + txHash = await core.token.transfer(accounts[0], { + from: sender.safeAddress, + to: receiver.safeAddress, + value, + paymentNote, + }); expect(web3.utils.isHexStrict(txHash)).toBe(true); }); @@ -164,15 +160,11 @@ describe('Token', () => { }); it('should return max flow and possible path when using pathfinder binary.', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps( - accounts[0], - { - from: safeAddresses[0], - to: safeAddresses[4], - value, - }, - 'cli', - ); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + }); expect(result.transferSteps.length).toBe(2); expect(result.transferSteps[0].from).toBe(safeAddresses[0]); expect(result.transferSteps[0].to).toBe(safeAddresses[3]); @@ -189,16 +181,12 @@ describe('Token', () => { }); it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps( - accounts[0], - { - from: safeAddresses[0], - to: safeAddresses[4], - value, - hops: 2, - }, - 'cli', - ); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + hops: 2, + }); expect(result.transferSteps.length).toBe(2); expect(result.transferSteps[0].from).toBe(safeAddresses[0]); expect(result.transferSteps[0].to).toBe(safeAddresses[3]); @@ -215,16 +203,12 @@ describe('Token', () => { }); it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps( - accounts[0], - { - from: safeAddresses[0], - to: safeAddresses[4], - value, - hops: 1, - }, - 'cli', - ); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + hops: 1, + }); expect(result.transferSteps.length).toBe(0); // The `pathfinder` stops searching for max flow as soon as it found a @@ -234,15 +218,11 @@ describe('Token', () => { }); it('should return max flow and possible path when using pathfinder server.', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps( - accounts[0], - { - from: safeAddresses[0], - to: safeAddresses[4], - value, - }, - 'server', - ); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + }); expect(result.transferSteps.length).toBe(2); expect(result.transferSteps[0].from).toBe(safeAddresses[0]); expect(result.transferSteps[0].to).toBe(safeAddresses[3]); @@ -259,16 +239,12 @@ describe('Token', () => { }); it('should return max flow and possible path when using max_transfers parameter in pathfinder server', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps( - accounts[0], - { - from: safeAddresses[0], - to: safeAddresses[4], - value, - maxTransfers: 2, - }, - 'server', - ); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + maxTransfers: 2, + }); expect(result.transferSteps.length).toBe(2); expect(result.transferSteps[0].from).toBe(safeAddresses[0]); expect(result.transferSteps[0].to).toBe(safeAddresses[3]); @@ -285,16 +261,12 @@ describe('Token', () => { }); it('should return 0 max flow and no path when using too low max_transfer parameter in pathfinder server', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps( - accounts[0], - { - from: safeAddresses[0], - to: safeAddresses[4], - value, - maxTransfers: 1, - }, - 'server', - ); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + maxTransfers: 1, + }); expect(result.transferSteps.length).toBe(0); // The `pathfinder` stops searching for max flow as soon as it found a // successful solution, therefore it returns a lower max flow than it @@ -431,15 +403,11 @@ describe('Token', () => { // Attempt to send an ammount which we know is higher // than the allowed by the blockchain data await expect( - core.token.transfer( - accounts[0], - { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - }, - 'cli', - ), + core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + }), ).rejects.toThrow(); const updateResult = await core.token.updateTransferSteps(accounts[0], { @@ -451,15 +419,11 @@ describe('Token', () => { expect(updateResult.updated).toBe(true); // Only after updating the path, the transfer can succeed - const response = await core.token.transfer( - accounts[0], - { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - }, - 'cli', - ); + const response = await core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + }); expect(web3.utils.isHexStrict(response)).toBe(true); }); From c8eeefc54f893622aa9026b873575a06ddbada30 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Wed, 8 Mar 2023 04:49:48 +0100 Subject: [PATCH 29/45] force build --- test/token.test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/token.test.js b/test/token.test.js index 331b68c6..5dd033ad 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -86,6 +86,7 @@ describe('Token', () => { core = createCore(); // Retrieve the value of the initial UBI payout (called signupBonus) from the deployed Hub contract + hubAddress = core.options.hubAddress; contracts = await getContracts(web3, { hubAddress: hubAddress, From 3ad411a754ec026dee57b1224e942ff01384ecfd Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Thu, 9 Mar 2023 21:18:19 +0100 Subject: [PATCH 30/45] update token and test --- src/token.js | 6 +- test/token.test.js | 623 +++++++++++++++++++++++---------------------- 2 files changed, 316 insertions(+), 313 deletions(-) diff --git a/src/token.js b/src/token.js index c2e98dff..5336357a 100644 --- a/src/token.js +++ b/src/token.js @@ -28,6 +28,7 @@ const MAX_TRANSFER_STEPS = 52; */ async function requestTransferSteps(web3, utils, userOptions, pathfinderType) { let result; + console.log('pathfinder type ', pathfinderType); if (pathfinderType == 'cli') { // call cli pathfinders result = await findTransitiveTransfer(web3, utils, userOptions); @@ -506,9 +507,10 @@ export default function createTokenModule( * * @return {string} - transaction hash */ - transfer: async (account, userOptions, pathfinderType = 'server') => { + transfer: async (account, userOptions, pathfinderType) => { checkAccount(web3, account); let fieldObject; + console.log('pathfinder type in transfer', pathfinderType); if (pathfinderType == 'cli') { fieldObject = { from: { @@ -608,7 +610,7 @@ export default function createTokenModule( }, ); } - + console.log('transferSteps response in transfer', response); if (response.transferSteps.length > MAX_TRANSFER_STEPS) { throw new TransferError( 'Too many transfer steps', diff --git a/test/token.test.js b/test/token.test.js index 5dd033ad..5bcb4611 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -115,7 +115,8 @@ describe('Token', () => { // Create sender and receiver Safe const sender = await deploySafeAndToken(core, accounts[0]); const receiver = await deploySafeAndToken(core, accounts[1]); - + console.log('sender', sender); + console.log('receiver', receiver); // Create a trust connection between receiver and sender await addTrustConnection(core, accounts[1], { user: sender.safeAddress, @@ -153,314 +154,314 @@ describe('Token', () => { }); }); - describe('Find transitive transfer steps', () => { - let safeAddresses; - beforeAll(async () => { - const result = await deployTestNetwork(core, accounts); - safeAddresses = result.safeAddresses; - }); - it('should return max flow and possible path when using pathfinder binary.', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - }); - it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - hops: 2, - }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - }); - it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - hops: 1, - }); - expect(result.transferSteps.length).toBe(0); - - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); - }); - it('should return max flow and possible path when using pathfinder server.', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - }); - it('should return max flow and possible path when using max_transfers parameter in pathfinder server', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - maxTransfers: 2, - }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - }); - it('should return 0 max flow and no path when using too low max_transfer parameter in pathfinder server', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - maxTransfers: 1, - }); - expect(result.transferSteps.length).toBe(0); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); - }); - }); - describe('Transitive Transactions', () => { - let safeAddresses; - let tokenAddresses; - - beforeAll(async () => { - const result = await deployTestNetwork(core, accounts); - safeAddresses = result.safeAddresses; - tokenAddresses = result.tokenAddresses; - }); - - it('should get the current balance', async () => { - const balance = await core.token.getBalance(accounts[5], { - safeAddress: safeAddresses[5], - }); - - // It should be equals the initial UBI payout (called signupBonus) which was set during Hub - // contract deployment: - expect(balance).toMatchObject(new web3.utils.BN(signupBonus)); - }); - - it('should send Circles to someone directly', async () => { - const value = web3.utils.toBN(core.utils.toFreckles(5)); - - // Unidirectional trust relationship from 1 to 2 - const indexFrom = 1; - const indexTo = 2; - - // Transfer from 1 to 2 - const response = await core.token.transfer(accounts[indexFrom], { - from: safeAddresses[indexFrom], - to: safeAddresses[indexTo], - value, - }); - - expect(web3.utils.isHexStrict(response)).toBe(true); - }); - - it('should send Circles to someone transitively', async () => { - const sentCircles = 5; - const value = web3.utils.toBN(core.utils.toFreckles(sentCircles)); - const indexFrom = 0; - const indexTo = 4; - - const response = await core.token.transfer(accounts[indexFrom], { - from: safeAddresses[indexFrom], - to: safeAddresses[indexTo], - value, - }); - - expect(web3.utils.isHexStrict(response)).toBe(true); - - const accountBalance = await loop( - 'Wait for balance to be lower after user transferred Circles', - () => { - return core.token.getBalance(accounts[indexFrom], { - safeAddress: safeAddresses[indexFrom], - }); - }, - (balance) => { - return ( - (core.utils.fromFreckles(balance) + 1).toString() === - (core.utils.fromFreckles(signupBonus) - sentCircles).toString() - ); - }, - ); - - const otherAccountBalance = await core.token.getBalance( - accounts[indexTo], - { - safeAddress: safeAddresses[indexTo], - }, - ); - - expect( - (core.utils.fromFreckles(otherAccountBalance) + 1).toString(), - ).toBe((core.utils.fromFreckles(signupBonus) + sentCircles).toString()); - expect((core.utils.fromFreckles(accountBalance) + 1).toString()).toBe( - (core.utils.fromFreckles(signupBonus) - sentCircles).toString(), - ); - }); - - it('should fail sending Circles when maxflow is lower than requested transfer value', async () => { - await expect( - core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles('100')), - }), - ).rejects.toThrow(); - }); - - it('should fail sending Circles when there is no trust path between sender and receiver', async () => { - // Trust connection does not exist between node 0 and 5 - await expect( - core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[5], - value: web3.utils.toBN('1'), - }), - ).rejects.toThrow(); - }); - - it('should fail to send Circles to someone transitively if maxTransfers value is too small to find a path', async () => { - await expect( - core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(5)), - maxTransfers: 1, - }), - ).rejects.toThrow(); - }); - - it('should fail sending Circles when data error when using the pathfinder binary', async () => { - // Update the edges.csv file simulating data error: - // Direct path does not exist between safeAddress 0 and 4, - // thus we create a false edge between safeAddress 0 and 4 - await Promise.resolve().then(() => { - let edgesCSVdata = `${safeAddresses[0]},${safeAddresses[4]},${safeAddresses[0]},100000000000000000000`; - execSync( - `docker exec circles-api bash -c "echo '${edgesCSVdata}' >> edges-data/edges.csv" `, - ); - }); - const valueToSend = '5'; - - // Then we perform the transfer expecting it to fail: - // Attempt to send an ammount which we know is higher - // than the allowed by the blockchain data - await expect( - core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - }), - ).rejects.toThrow(); - - const updateResult = await core.token.updateTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - }); - await wait(3000); - expect(updateResult.updated).toBe(true); - - // Only after updating the path, the transfer can succeed - const response = await core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - }); - expect(web3.utils.isHexStrict(response)).toBe(true); - }); - - describe('requestUBIPayout', () => { - let token; - let payout; - - beforeAll(async () => { - token = await getTokenContract(web3, tokenAddresses[5]); - - payout = await core.token.checkUBIPayout(accounts[5], { - safeAddress: safeAddresses[5], - }); - }); - - it('should add the next payout to our balance', async () => { - const balanceBefore = await token.methods - .balanceOf(safeAddresses[5]) - .call(); - - await core.token.requestUBIPayout(accounts[5], { - safeAddress: safeAddresses[5], - }); - - const balanceAfter = await token.methods - .balanceOf(safeAddresses[5]) - .call(); - - const expectedBalance = web3.utils - .toBN(balanceBefore) - .add(payout) - .toString(); - - // Do not check for the exact amount as payout is changing every second - expect(web3.utils.toBN(balanceAfter).gt(expectedBalance)).toBe(true); - }); - }); - }); + // describe('Find transitive transfer steps', () => { + // let safeAddresses; + // beforeAll(async () => { + // const result = await deployTestNetwork(core, accounts); + // safeAddresses = result.safeAddresses; + // }); + // it('should return max flow and possible path when using pathfinder binary.', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // }); + // expect(result.transferSteps.length).toBe(2); + // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); + // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + // }); + // it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // hops: 2, + // }); + // expect(result.transferSteps.length).toBe(2); + // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); + // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + // }); + // it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // hops: 1, + // }); + // expect(result.transferSteps.length).toBe(0); + + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); + // }); + // it('should return max flow and possible path when using pathfinder server.', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // }); + // expect(result.transferSteps.length).toBe(2); + // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); + // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + // }); + // it('should return max flow and possible path when using max_transfers parameter in pathfinder server', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // maxTransfers: 2, + // }); + // expect(result.transferSteps.length).toBe(2); + // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); + // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + // }); + // it('should return 0 max flow and no path when using too low max_transfer parameter in pathfinder server', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // maxTransfers: 1, + // }); + // expect(result.transferSteps.length).toBe(0); + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); + // }); + // }); + // describe('Transitive Transactions', () => { + // let safeAddresses; + // let tokenAddresses; + + // beforeAll(async () => { + // const result = await deployTestNetwork(core, accounts); + // safeAddresses = result.safeAddresses; + // tokenAddresses = result.tokenAddresses; + // }); + + // it('should get the current balance', async () => { + // const balance = await core.token.getBalance(accounts[5], { + // safeAddress: safeAddresses[5], + // }); + + // // It should be equals the initial UBI payout (called signupBonus) which was set during Hub + // // contract deployment: + // expect(balance).toMatchObject(new web3.utils.BN(signupBonus)); + // }); + + // it('should send Circles to someone directly', async () => { + // const value = web3.utils.toBN(core.utils.toFreckles(5)); + + // // Unidirectional trust relationship from 1 to 2 + // const indexFrom = 1; + // const indexTo = 2; + + // // Transfer from 1 to 2 + // const response = await core.token.transfer(accounts[indexFrom], { + // from: safeAddresses[indexFrom], + // to: safeAddresses[indexTo], + // value, + // }); + + // expect(web3.utils.isHexStrict(response)).toBe(true); + // }); + + // it('should send Circles to someone transitively', async () => { + // const sentCircles = 5; + // const value = web3.utils.toBN(core.utils.toFreckles(sentCircles)); + // const indexFrom = 0; + // const indexTo = 4; + + // const response = await core.token.transfer(accounts[indexFrom], { + // from: safeAddresses[indexFrom], + // to: safeAddresses[indexTo], + // value, + // }); + + // expect(web3.utils.isHexStrict(response)).toBe(true); + + // const accountBalance = await loop( + // 'Wait for balance to be lower after user transferred Circles', + // () => { + // return core.token.getBalance(accounts[indexFrom], { + // safeAddress: safeAddresses[indexFrom], + // }); + // }, + // (balance) => { + // return ( + // (core.utils.fromFreckles(balance) + 1).toString() === + // (core.utils.fromFreckles(signupBonus) - sentCircles).toString() + // ); + // }, + // ); + + // const otherAccountBalance = await core.token.getBalance( + // accounts[indexTo], + // { + // safeAddress: safeAddresses[indexTo], + // }, + // ); + + // expect( + // (core.utils.fromFreckles(otherAccountBalance) + 1).toString(), + // ).toBe((core.utils.fromFreckles(signupBonus) + sentCircles).toString()); + // expect((core.utils.fromFreckles(accountBalance) + 1).toString()).toBe( + // (core.utils.fromFreckles(signupBonus) - sentCircles).toString(), + // ); + // }); + + // it('should fail sending Circles when maxflow is lower than requested transfer value', async () => { + // await expect( + // core.token.transfer(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value: web3.utils.toBN(core.utils.toFreckles('100')), + // }), + // ).rejects.toThrow(); + // }); + + // it('should fail sending Circles when there is no trust path between sender and receiver', async () => { + // // Trust connection does not exist between node 0 and 5 + // await expect( + // core.token.transfer(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[5], + // value: web3.utils.toBN('1'), + // }), + // ).rejects.toThrow(); + // }); + + // it('should fail to send Circles to someone transitively if maxTransfers value is too small to find a path', async () => { + // await expect( + // core.token.transfer(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value: web3.utils.toBN(core.utils.toFreckles(5)), + // maxTransfers: 1, + // }), + // ).rejects.toThrow(); + // }); + + // // it('should fail sending Circles when data error when using the pathfinder binary', async () => { + // // // Update the edges.csv file simulating data error: + // // // Direct path does not exist between safeAddress 0 and 4, + // // // thus we create a false edge between safeAddress 0 and 4 + // // await Promise.resolve().then(() => { + // // let edgesCSVdata = `${safeAddresses[0]},${safeAddresses[4]},${safeAddresses[0]},100000000000000000000`; + // // execSync( + // // `docker exec circles-api bash -c "echo '${edgesCSVdata}' >> edges-data/edges.csv" `, + // // ); + // // }); + // // const valueToSend = '5'; + + // // // Then we perform the transfer expecting it to fail: + // // // Attempt to send an ammount which we know is higher + // // // than the allowed by the blockchain data + // // await expect( + // // core.token.transfer(accounts[0], { + // // from: safeAddresses[0], + // // to: safeAddresses[4], + // // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + // // }), + // // ).rejects.toThrow(); + + // // const updateResult = await core.token.updateTransferSteps(accounts[0], { + // // from: safeAddresses[0], + // // to: safeAddresses[4], + // // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + // // }); + // // await wait(3000); + // // expect(updateResult.updated).toBe(true); + + // // // Only after updating the path, the transfer can succeed + // // const response = await core.token.transfer(accounts[0], { + // // from: safeAddresses[0], + // // to: safeAddresses[4], + // // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + // // }); + // // expect(web3.utils.isHexStrict(response)).toBe(true); + // // }); + + // describe('requestUBIPayout', () => { + // let token; + // let payout; + + // beforeAll(async () => { + // token = await getTokenContract(web3, tokenAddresses[5]); + + // payout = await core.token.checkUBIPayout(accounts[5], { + // safeAddress: safeAddresses[5], + // }); + // }); + + // it('should add the next payout to our balance', async () => { + // const balanceBefore = await token.methods + // .balanceOf(safeAddresses[5]) + // .call(); + + // await core.token.requestUBIPayout(accounts[5], { + // safeAddress: safeAddresses[5], + // }); + + // const balanceAfter = await token.methods + // .balanceOf(safeAddresses[5]) + // .call(); + + // const expectedBalance = web3.utils + // .toBN(balanceBefore) + // .add(payout) + // .toString(); + + // // Do not check for the exact amount as payout is changing every second + // expect(web3.utils.toBN(balanceAfter).gt(expectedBalance)).toBe(true); + // }); + // }); + // }); }); From 5768fea617c555230f58c68a50aa74c62af086c0 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Thu, 9 Mar 2023 21:43:29 +0100 Subject: [PATCH 31/45] update test and token code --- src/token.js | 3 +- test/token.test.js | 620 ++++++++++++++++++++++----------------------- 2 files changed, 311 insertions(+), 312 deletions(-) diff --git a/src/token.js b/src/token.js index 5336357a..3a744ca2 100644 --- a/src/token.js +++ b/src/token.js @@ -503,11 +503,10 @@ export default function createTokenModule( * @param {BN} userOptions.value - value * @param {string} userOptions.paymentNote - optional payment note stored in API * @param {number} userOptions.hops - maximum number of trust hops away from them sending user inside the trust network for finding transaction steps - * @param {string} pathfinderType - "cli" or "server" * * @return {string} - transaction hash */ - transfer: async (account, userOptions, pathfinderType) => { + transfer: async (account, userOptions) => { checkAccount(web3, account); let fieldObject; console.log('pathfinder type in transfer', pathfinderType); diff --git a/test/token.test.js b/test/token.test.js index 5bcb4611..2acac9d7 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -154,314 +154,314 @@ describe('Token', () => { }); }); - // describe('Find transitive transfer steps', () => { - // let safeAddresses; - // beforeAll(async () => { - // const result = await deployTestNetwork(core, accounts); - // safeAddresses = result.safeAddresses; - // }); - // it('should return max flow and possible path when using pathfinder binary.', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // }); - // expect(result.transferSteps.length).toBe(2); - // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - // }); - // it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // hops: 2, - // }); - // expect(result.transferSteps.length).toBe(2); - // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - // }); - // it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // hops: 1, - // }); - // expect(result.transferSteps.length).toBe(0); - - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); - // }); - // it('should return max flow and possible path when using pathfinder server.', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // }); - // expect(result.transferSteps.length).toBe(2); - // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); - // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - // }); - // it('should return max flow and possible path when using max_transfers parameter in pathfinder server', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // maxTransfers: 2, - // }); - // expect(result.transferSteps.length).toBe(2); - // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); - // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - // }); - // it('should return 0 max flow and no path when using too low max_transfer parameter in pathfinder server', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // maxTransfers: 1, - // }); - // expect(result.transferSteps.length).toBe(0); - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); - // }); - // }); - // describe('Transitive Transactions', () => { - // let safeAddresses; - // let tokenAddresses; - - // beforeAll(async () => { - // const result = await deployTestNetwork(core, accounts); - // safeAddresses = result.safeAddresses; - // tokenAddresses = result.tokenAddresses; - // }); - - // it('should get the current balance', async () => { - // const balance = await core.token.getBalance(accounts[5], { - // safeAddress: safeAddresses[5], - // }); - - // // It should be equals the initial UBI payout (called signupBonus) which was set during Hub - // // contract deployment: - // expect(balance).toMatchObject(new web3.utils.BN(signupBonus)); - // }); - - // it('should send Circles to someone directly', async () => { - // const value = web3.utils.toBN(core.utils.toFreckles(5)); - - // // Unidirectional trust relationship from 1 to 2 - // const indexFrom = 1; - // const indexTo = 2; - - // // Transfer from 1 to 2 - // const response = await core.token.transfer(accounts[indexFrom], { - // from: safeAddresses[indexFrom], - // to: safeAddresses[indexTo], - // value, - // }); - - // expect(web3.utils.isHexStrict(response)).toBe(true); - // }); - - // it('should send Circles to someone transitively', async () => { - // const sentCircles = 5; - // const value = web3.utils.toBN(core.utils.toFreckles(sentCircles)); - // const indexFrom = 0; - // const indexTo = 4; - - // const response = await core.token.transfer(accounts[indexFrom], { - // from: safeAddresses[indexFrom], - // to: safeAddresses[indexTo], - // value, - // }); - - // expect(web3.utils.isHexStrict(response)).toBe(true); - - // const accountBalance = await loop( - // 'Wait for balance to be lower after user transferred Circles', - // () => { - // return core.token.getBalance(accounts[indexFrom], { - // safeAddress: safeAddresses[indexFrom], - // }); - // }, - // (balance) => { - // return ( - // (core.utils.fromFreckles(balance) + 1).toString() === - // (core.utils.fromFreckles(signupBonus) - sentCircles).toString() - // ); - // }, - // ); - - // const otherAccountBalance = await core.token.getBalance( - // accounts[indexTo], - // { - // safeAddress: safeAddresses[indexTo], - // }, - // ); - - // expect( - // (core.utils.fromFreckles(otherAccountBalance) + 1).toString(), - // ).toBe((core.utils.fromFreckles(signupBonus) + sentCircles).toString()); - // expect((core.utils.fromFreckles(accountBalance) + 1).toString()).toBe( - // (core.utils.fromFreckles(signupBonus) - sentCircles).toString(), - // ); - // }); - - // it('should fail sending Circles when maxflow is lower than requested transfer value', async () => { - // await expect( - // core.token.transfer(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value: web3.utils.toBN(core.utils.toFreckles('100')), - // }), - // ).rejects.toThrow(); - // }); - - // it('should fail sending Circles when there is no trust path between sender and receiver', async () => { - // // Trust connection does not exist between node 0 and 5 - // await expect( - // core.token.transfer(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[5], - // value: web3.utils.toBN('1'), - // }), - // ).rejects.toThrow(); - // }); - - // it('should fail to send Circles to someone transitively if maxTransfers value is too small to find a path', async () => { - // await expect( - // core.token.transfer(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value: web3.utils.toBN(core.utils.toFreckles(5)), - // maxTransfers: 1, - // }), - // ).rejects.toThrow(); - // }); - - // // it('should fail sending Circles when data error when using the pathfinder binary', async () => { - // // // Update the edges.csv file simulating data error: - // // // Direct path does not exist between safeAddress 0 and 4, - // // // thus we create a false edge between safeAddress 0 and 4 - // // await Promise.resolve().then(() => { - // // let edgesCSVdata = `${safeAddresses[0]},${safeAddresses[4]},${safeAddresses[0]},100000000000000000000`; - // // execSync( - // // `docker exec circles-api bash -c "echo '${edgesCSVdata}' >> edges-data/edges.csv" `, - // // ); - // // }); - // // const valueToSend = '5'; - - // // // Then we perform the transfer expecting it to fail: - // // // Attempt to send an ammount which we know is higher - // // // than the allowed by the blockchain data - // // await expect( - // // core.token.transfer(accounts[0], { - // // from: safeAddresses[0], - // // to: safeAddresses[4], - // // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - // // }), - // // ).rejects.toThrow(); - - // // const updateResult = await core.token.updateTransferSteps(accounts[0], { - // // from: safeAddresses[0], - // // to: safeAddresses[4], - // // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - // // }); - // // await wait(3000); - // // expect(updateResult.updated).toBe(true); - - // // // Only after updating the path, the transfer can succeed - // // const response = await core.token.transfer(accounts[0], { - // // from: safeAddresses[0], - // // to: safeAddresses[4], - // // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - // // }); - // // expect(web3.utils.isHexStrict(response)).toBe(true); - // // }); - - // describe('requestUBIPayout', () => { - // let token; - // let payout; - - // beforeAll(async () => { - // token = await getTokenContract(web3, tokenAddresses[5]); - - // payout = await core.token.checkUBIPayout(accounts[5], { - // safeAddress: safeAddresses[5], - // }); - // }); - - // it('should add the next payout to our balance', async () => { - // const balanceBefore = await token.methods - // .balanceOf(safeAddresses[5]) - // .call(); - - // await core.token.requestUBIPayout(accounts[5], { - // safeAddress: safeAddresses[5], - // }); - - // const balanceAfter = await token.methods - // .balanceOf(safeAddresses[5]) - // .call(); - - // const expectedBalance = web3.utils - // .toBN(balanceBefore) - // .add(payout) - // .toString(); - - // // Do not check for the exact amount as payout is changing every second - // expect(web3.utils.toBN(balanceAfter).gt(expectedBalance)).toBe(true); - // }); - // }); - // }); + describe('Find transitive transfer steps', () => { + let safeAddresses; + beforeAll(async () => { + const result = await deployTestNetwork(core, accounts); + safeAddresses = result.safeAddresses; + }); + it('should return max flow and possible path when using pathfinder binary.', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + }); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + }); + it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + hops: 2, + }); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + }); + it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + hops: 1, + }); + expect(result.transferSteps.length).toBe(0); + + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); + }); + it('should return max flow and possible path when using pathfinder server.', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + }); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + }); + it('should return max flow and possible path when using max_transfers parameter in pathfinder server', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + maxTransfers: 2, + }); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + }); + it('should return 0 max flow and no path when using too low max_transfer parameter in pathfinder server', async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + maxTransfers: 1, + }); + expect(result.transferSteps.length).toBe(0); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); + }); + }); + describe('Transitive Transactions', () => { + let safeAddresses; + let tokenAddresses; + + beforeAll(async () => { + const result = await deployTestNetwork(core, accounts); + safeAddresses = result.safeAddresses; + tokenAddresses = result.tokenAddresses; + }); + + it('should get the current balance', async () => { + const balance = await core.token.getBalance(accounts[5], { + safeAddress: safeAddresses[5], + }); + + // It should be equals the initial UBI payout (called signupBonus) which was set during Hub + // contract deployment: + expect(balance).toMatchObject(new web3.utils.BN(signupBonus)); + }); + + it('should send Circles to someone directly', async () => { + const value = web3.utils.toBN(core.utils.toFreckles(5)); + + // Unidirectional trust relationship from 1 to 2 + const indexFrom = 1; + const indexTo = 2; + + // Transfer from 1 to 2 + const response = await core.token.transfer(accounts[indexFrom], { + from: safeAddresses[indexFrom], + to: safeAddresses[indexTo], + value, + }); + + expect(web3.utils.isHexStrict(response)).toBe(true); + }); + + it('should send Circles to someone transitively', async () => { + const sentCircles = 5; + const value = web3.utils.toBN(core.utils.toFreckles(sentCircles)); + const indexFrom = 0; + const indexTo = 4; + + const response = await core.token.transfer(accounts[indexFrom], { + from: safeAddresses[indexFrom], + to: safeAddresses[indexTo], + value, + }); + + expect(web3.utils.isHexStrict(response)).toBe(true); + + const accountBalance = await loop( + 'Wait for balance to be lower after user transferred Circles', + () => { + return core.token.getBalance(accounts[indexFrom], { + safeAddress: safeAddresses[indexFrom], + }); + }, + (balance) => { + return ( + (core.utils.fromFreckles(balance) + 1).toString() === + (core.utils.fromFreckles(signupBonus) - sentCircles).toString() + ); + }, + ); + + const otherAccountBalance = await core.token.getBalance( + accounts[indexTo], + { + safeAddress: safeAddresses[indexTo], + }, + ); + + expect( + (core.utils.fromFreckles(otherAccountBalance) + 1).toString(), + ).toBe((core.utils.fromFreckles(signupBonus) + sentCircles).toString()); + expect((core.utils.fromFreckles(accountBalance) + 1).toString()).toBe( + (core.utils.fromFreckles(signupBonus) - sentCircles).toString(), + ); + }); + + it('should fail sending Circles when maxflow is lower than requested transfer value', async () => { + await expect( + core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles('100')), + }), + ).rejects.toThrow(); + }); + + it('should fail sending Circles when there is no trust path between sender and receiver', async () => { + // Trust connection does not exist between node 0 and 5 + await expect( + core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[5], + value: web3.utils.toBN('1'), + }), + ).rejects.toThrow(); + }); + + it('should fail to send Circles to someone transitively if maxTransfers value is too small to find a path', async () => { + await expect( + core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(5)), + maxTransfers: 1, + }), + ).rejects.toThrow(); + }); + + // it('should fail sending Circles when data error when using the pathfinder binary', async () => { + // // Update the edges.csv file simulating data error: + // // Direct path does not exist between safeAddress 0 and 4, + // // thus we create a false edge between safeAddress 0 and 4 + // await Promise.resolve().then(() => { + // let edgesCSVdata = `${safeAddresses[0]},${safeAddresses[4]},${safeAddresses[0]},100000000000000000000`; + // execSync( + // `docker exec circles-api bash -c "echo '${edgesCSVdata}' >> edges-data/edges.csv" `, + // ); + // }); + // const valueToSend = '5'; + + // // Then we perform the transfer expecting it to fail: + // // Attempt to send an ammount which we know is higher + // // than the allowed by the blockchain data + // await expect( + // core.token.transfer(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + // }), + // ).rejects.toThrow(); + + // const updateResult = await core.token.updateTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + // }); + // await wait(3000); + // expect(updateResult.updated).toBe(true); + + // // Only after updating the path, the transfer can succeed + // const response = await core.token.transfer(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + // }); + // expect(web3.utils.isHexStrict(response)).toBe(true); + // }); + + describe('requestUBIPayout', () => { + let token; + let payout; + + beforeAll(async () => { + token = await getTokenContract(web3, tokenAddresses[5]); + + payout = await core.token.checkUBIPayout(accounts[5], { + safeAddress: safeAddresses[5], + }); + }); + + it('should add the next payout to our balance', async () => { + const balanceBefore = await token.methods + .balanceOf(safeAddresses[5]) + .call(); + + await core.token.requestUBIPayout(accounts[5], { + safeAddress: safeAddresses[5], + }); + + const balanceAfter = await token.methods + .balanceOf(safeAddresses[5]) + .call(); + + const expectedBalance = web3.utils + .toBN(balanceBefore) + .add(payout) + .toString(); + + // Do not check for the exact amount as payout is changing every second + expect(web3.utils.toBN(balanceAfter).gt(expectedBalance)).toBe(true); + }); + }); + }); }); From 0d5daeb2b5f63263d8f4cb083de0c5c3b23bd7f2 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Thu, 9 Mar 2023 22:02:28 +0100 Subject: [PATCH 32/45] remove console statements --- src/token.js | 3 --- test/token.test.js | 2 -- 2 files changed, 5 deletions(-) diff --git a/src/token.js b/src/token.js index 3a744ca2..0b1c1c9a 100644 --- a/src/token.js +++ b/src/token.js @@ -28,7 +28,6 @@ const MAX_TRANSFER_STEPS = 52; */ async function requestTransferSteps(web3, utils, userOptions, pathfinderType) { let result; - console.log('pathfinder type ', pathfinderType); if (pathfinderType == 'cli') { // call cli pathfinders result = await findTransitiveTransfer(web3, utils, userOptions); @@ -509,7 +508,6 @@ export default function createTokenModule( transfer: async (account, userOptions) => { checkAccount(web3, account); let fieldObject; - console.log('pathfinder type in transfer', pathfinderType); if (pathfinderType == 'cli') { fieldObject = { from: { @@ -609,7 +607,6 @@ export default function createTokenModule( }, ); } - console.log('transferSteps response in transfer', response); if (response.transferSteps.length > MAX_TRANSFER_STEPS) { throw new TransferError( 'Too many transfer steps', diff --git a/test/token.test.js b/test/token.test.js index 2acac9d7..87dacad9 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -115,8 +115,6 @@ describe('Token', () => { // Create sender and receiver Safe const sender = await deploySafeAndToken(core, accounts[0]); const receiver = await deploySafeAndToken(core, accounts[1]); - console.log('sender', sender); - console.log('receiver', receiver); // Create a trust connection between receiver and sender await addTrustConnection(core, accounts[1], { user: sender.safeAddress, From 6f178f78f26fea482ec70468062abad5fe0be9bf Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Fri, 10 Mar 2023 17:14:32 +0100 Subject: [PATCH 33/45] run token test --- test/token.test.js | 128 +++++++++++++++++++++++---------------------- 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/test/token.test.js b/test/token.test.js index 87dacad9..8db01ee5 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -1,4 +1,4 @@ -import { execSync } from 'child_process'; +// import { execSync } from 'child_process'; import { getTokenContract } from '~/common/getContracts'; import getContracts from '~/common/getContracts'; @@ -28,11 +28,11 @@ const TEST_TRUST_NETWORK = [ [2, 5, 50], // Unidirectional ]; -async function wait(ms) { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); -} +// async function wait(ms) { +// return new Promise((resolve) => { +// setTimeout(resolve, ms); +// }); +// } async function deployTestNetwork( core, @@ -115,6 +115,8 @@ describe('Token', () => { // Create sender and receiver Safe const sender = await deploySafeAndToken(core, accounts[0]); const receiver = await deploySafeAndToken(core, accounts[1]); + console.log('sender', sender); + console.log('receiver', receiver); // Create a trust connection between receiver and sender await addTrustConnection(core, accounts[1], { user: sender.safeAddress, @@ -158,64 +160,64 @@ describe('Token', () => { const result = await deployTestNetwork(core, accounts); safeAddresses = result.safeAddresses; }); - it('should return max flow and possible path when using pathfinder binary.', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - }); - it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - hops: 2, - }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - }); - it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - hops: 1, - }); - expect(result.transferSteps.length).toBe(0); + // it('should return max flow and possible path when using pathfinder binary.', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // }); + // expect(result.transferSteps.length).toBe(2); + // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); + // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + // }); + // it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // hops: 2, + // }); + // expect(result.transferSteps.length).toBe(2); + // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); + // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + // expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); + // }); + // it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { + // const value = new web3.utils.BN(core.utils.toFreckles(1)); + // const result = await core.token.requestTransferSteps(accounts[0], { + // from: safeAddresses[0], + // to: safeAddresses[4], + // value, + // hops: 1, + // }); + // expect(result.transferSteps.length).toBe(0); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); - }); + // // The `pathfinder` stops searching for max flow as soon as it found a + // // successful solution, therefore it returns a lower max flow than it + // // actually is (25). + // expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); + // }); it('should return max flow and possible path when using pathfinder server.', async () => { const value = new web3.utils.BN(core.utils.toFreckles(1)); const result = await core.token.requestTransferSteps(accounts[0], { From 5cdaf7f88ef67a434cc634817c6e05f82dec0079 Mon Sep 17 00:00:00 2001 From: JacqueGM Date: Fri, 10 Mar 2023 17:31:36 +0100 Subject: [PATCH 34/45] remove console.log --- test/token.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/token.test.js b/test/token.test.js index 8db01ee5..a4d4da2c 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -115,8 +115,6 @@ describe('Token', () => { // Create sender and receiver Safe const sender = await deploySafeAndToken(core, accounts[0]); const receiver = await deploySafeAndToken(core, accounts[1]); - console.log('sender', sender); - console.log('receiver', receiver); // Create a trust connection between receiver and sender await addTrustConnection(core, accounts[1], { user: sender.safeAddress, From e7555a0d9b17bc30bef0ac371d8b4b2478331705 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Thu, 16 Mar 2023 10:00:46 +0100 Subject: [PATCH 35/45] Add loop for token deployment in token tests --- test/helpers/transactions.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/helpers/transactions.js b/test/helpers/transactions.js index 9a7ac2e8..a96febb3 100644 --- a/test/helpers/transactions.js +++ b/test/helpers/transactions.js @@ -44,6 +44,16 @@ export async function deploySafe(core, account) { export async function deployToken(core, account, userOptions) { await core.token.deploy(account, userOptions); + // Wait until token deployed + await loop( + () => { + return core.token.getAddress(core, account, safeAddress); + }, + (address) => { + return address !== ZERO_ADDRESS; + }, + ); + const tokenAddress = await core.token.getAddress(account, userOptions); return tokenAddress; From 66f803960c77a49d7ad71c1a0e790e2e34bac473 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Thu, 16 Mar 2023 10:48:36 +0100 Subject: [PATCH 36/45] Deploy test network only once in token tests --- test/token.test.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/test/token.test.js b/test/token.test.js index a4d4da2c..fe81f2f1 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -77,6 +77,8 @@ describe('Token', () => { let signupBonus; let contracts; let hubAddress; + let safeAddresses; + let tokenAddresses; beforeAll(async () => { accounts = new Array(6).fill({}).map((item, index) => { @@ -95,6 +97,10 @@ describe('Token', () => { }); const { hub } = contracts; signupBonus = await hub.methods.signupBonus().call(); + + const result = await deployTestNetwork(core, accounts); + safeAddresses = result.safeAddresses; + tokenAddresses = result.tokenAddresses; }); it('should check if safe has enough funds for token to be deployed', async () => { @@ -153,11 +159,7 @@ describe('Token', () => { }); describe('Find transitive transfer steps', () => { - let safeAddresses; - beforeAll(async () => { - const result = await deployTestNetwork(core, accounts); - safeAddresses = result.safeAddresses; - }); + // it('should return max flow and possible path when using pathfinder binary.', async () => { // const value = new web3.utils.BN(core.utils.toFreckles(1)); // const result = await core.token.requestTransferSteps(accounts[0], { @@ -275,14 +277,6 @@ describe('Token', () => { }); }); describe('Transitive Transactions', () => { - let safeAddresses; - let tokenAddresses; - - beforeAll(async () => { - const result = await deployTestNetwork(core, accounts); - safeAddresses = result.safeAddresses; - tokenAddresses = result.tokenAddresses; - }); it('should get the current balance', async () => { const balance = await core.token.getBalance(accounts[5], { From 375d66abf2722de258dae00ef76297285ebf8bde Mon Sep 17 00:00:00 2001 From: Juan Enrique Alcaraz Date: Thu, 16 Mar 2023 10:51:23 +0100 Subject: [PATCH 37/45] Set max transfer steps value to 30 --- src/token.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/token.js b/src/token.js index 0b1c1c9a..7d456a51 100644 --- a/src/token.js +++ b/src/token.js @@ -11,7 +11,7 @@ import { getVersion } from '~/safe'; * gas estimate and the block gas limit. * For more information, see the Circles handbook. */ -const MAX_TRANSFER_STEPS = 52; +const MAX_TRANSFER_STEPS = 30; /** * Find maximumFlow and transfer steps through a trust graph from someone to @@ -545,7 +545,7 @@ export default function createTokenModule( }, maxTransfers: { type: 'number', - default: 40, + default: MAX_TRANSFER_STEPS, }, pathfinderMethod: { type: 'string', From 51ec5dc92240f5596321c1b54591fa9438711c30 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Thu, 16 Mar 2023 10:55:51 +0100 Subject: [PATCH 38/45] Make lint happy --- .github/workflows/tests.yml | 4 ++-- src/token.js | 1 + test/helpers/transactions.js | 2 +- test/token.test.js | 2 -- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1491805c..1b4527f5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -58,7 +58,7 @@ jobs: - name: Container setup via docker-compose without pathfinder working-directory: circles-docker - run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -p circles up --detach --remove-orphans --build + run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -p circles up --detach --remove-orphans --build - name: Download and migrate contracts working-directory: circles-docker @@ -72,7 +72,7 @@ jobs: - name: Create and deploy subgraph working-directory: circles-docker run: ./scripts/deploy-subgraph.sh - + - name: Try starting failed services working-directory: circles-docker run: docker compose -f docker-compose.yml -f docker-compose.relayer-pull.yml -f docker-compose.api-pull.yml -p circles up --detach --remove-orphans --build diff --git a/src/token.js b/src/token.js index 7d456a51..1ef9590d 100644 --- a/src/token.js +++ b/src/token.js @@ -71,6 +71,7 @@ export async function findTransitiveTransfer(web3, utils, userOptions) { default: 3, }, }); + try { const response = await utils.requestAPI({ path: ['transfers'], diff --git a/test/helpers/transactions.js b/test/helpers/transactions.js index a96febb3..6d99ab49 100644 --- a/test/helpers/transactions.js +++ b/test/helpers/transactions.js @@ -47,7 +47,7 @@ export async function deployToken(core, account, userOptions) { // Wait until token deployed await loop( () => { - return core.token.getAddress(core, account, safeAddress); + return core.token.getAddress(core, account, userOptions.safeAddress); }, (address) => { return address !== ZERO_ADDRESS; diff --git a/test/token.test.js b/test/token.test.js index fe81f2f1..08c31724 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -159,7 +159,6 @@ describe('Token', () => { }); describe('Find transitive transfer steps', () => { - // it('should return max flow and possible path when using pathfinder binary.', async () => { // const value = new web3.utils.BN(core.utils.toFreckles(1)); // const result = await core.token.requestTransferSteps(accounts[0], { @@ -277,7 +276,6 @@ describe('Token', () => { }); }); describe('Transitive Transactions', () => { - it('should get the current balance', async () => { const balance = await core.token.getBalance(accounts[5], { safeAddress: safeAddresses[5], From d3ca971201c0124f6f2b3354174a4feb7613dff7 Mon Sep 17 00:00:00 2001 From: Juan Enrique Alcaraz Date: Thu, 16 Mar 2023 11:12:20 +0100 Subject: [PATCH 39/45] Parameterize core pathfinder type for testing --- test/helpers/core.js | 3 +- test/token.test.js | 648 ++++++++++++++++++++----------------------- 2 files changed, 308 insertions(+), 343 deletions(-) diff --git a/test/helpers/core.js b/test/helpers/core.js index a8d63bd7..006a3f1b 100644 --- a/test/helpers/core.js +++ b/test/helpers/core.js @@ -2,7 +2,7 @@ import CirclesCore from '~'; import web3 from './web3'; -export default function createCore() { +export default function createCore(opts) { return new CirclesCore(web3, { apiServiceEndpoint: process.env.API_SERVICE_ENDPOINT, fallbackHandlerAddress: process.env.SAFE_DEFAULT_CALLBACK_HANDLER, @@ -14,5 +14,6 @@ export default function createCore() { relayServiceEndpoint: process.env.RELAY_SERVICE_ENDPOINT, safeMasterAddress: process.env.SAFE_ADDRESS, subgraphName: process.env.SUBGRAPH_NAME, + ...opts, }); } diff --git a/test/token.test.js b/test/token.test.js index 08c31724..22376f68 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -1,4 +1,4 @@ -// import { execSync } from 'child_process'; +import { execSync } from 'child_process'; import { getTokenContract } from '~/common/getContracts'; import getContracts from '~/common/getContracts'; @@ -28,11 +28,11 @@ const TEST_TRUST_NETWORK = [ [2, 5, 50], // Unidirectional ]; -// async function wait(ms) { -// return new Promise((resolve) => { -// setTimeout(resolve, ms); -// }); -// } +async function wait(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} async function deployTestNetwork( core, @@ -71,387 +71,351 @@ async function deployTestNetwork( }; } -describe('Token', () => { - let core; - let accounts; - let signupBonus; - let contracts; - let hubAddress; - let safeAddresses; - let tokenAddresses; - - beforeAll(async () => { - accounts = new Array(6).fill({}).map((item, index) => { - return getAccount(index); - }); +const executeTests = (core) => { + describe('Token', () => { + let accounts; + let signupBonus; + let contracts; + let hubAddress; + let safeAddresses; + let tokenAddresses; + const isPathfinderServer = core.options.pathfinderType === 'server'; + const testPathfinderName = isPathfinderServer ? 'server' : 'binary'; + const tokenOwnerAddressProperty = isPathfinderServer + ? 'token_owner' + : 'tokenOwnerAddress'; + const transferStepsProperty = isPathfinderServer ? 'maxTransfers' : 'hops'; + + beforeAll(async () => { + accounts = new Array(6).fill({}).map((item, index) => { + return getAccount(index); + }); + // Retrieve the value of the initial UBI payout (called signupBonus) from the deployed Hub contract - core = createCore(); + hubAddress = core.options.hubAddress; + contracts = await getContracts(web3, { + hubAddress: hubAddress, + proxyFactoryAddress: ZERO_ADDRESS, + safeMasterAddress: ZERO_ADDRESS, + }); + const { hub } = contracts; + signupBonus = await hub.methods.signupBonus().call(); - // Retrieve the value of the initial UBI payout (called signupBonus) from the deployed Hub contract + const result = await deployTestNetwork(core, accounts); - hubAddress = core.options.hubAddress; - contracts = await getContracts(web3, { - hubAddress: hubAddress, - proxyFactoryAddress: ZERO_ADDRESS, - safeMasterAddress: ZERO_ADDRESS, + safeAddresses = result.safeAddresses; + tokenAddresses = result.tokenAddresses; }); - const { hub } = contracts; - signupBonus = await hub.methods.signupBonus().call(); - const result = await deployTestNetwork(core, accounts); - safeAddresses = result.safeAddresses; - tokenAddresses = result.tokenAddresses; - }); + it('should check if safe has enough funds for token to be deployed', async () => { + const safeAddress = await deploySafe(core, accounts[0]); - it('should check if safe has enough funds for token to be deployed', async () => { - const safeAddress = await deploySafe(core, accounts[0]); + expect( + await core.token.isFunded(accounts[0], { + safeAddress, + }), + ).toBe(true); + }); - expect( - await core.token.isFunded(accounts[0], { - safeAddress, - }), - ).toBe(true); - }); + describe('Payment notes', () => { + let paymentNote; + let txHash; - describe('Payment notes', () => { - let paymentNote; - let txHash; + beforeAll(async () => { + // Create sender and receiver Safe + const sender = await deploySafeAndToken(core, accounts[0]); + const receiver = await deploySafeAndToken(core, accounts[1]); + // Create a trust connection between receiver and sender + await addTrustConnection(core, accounts[1], { + user: sender.safeAddress, + canSendTo: receiver.safeAddress, + limitPercentage: 50, + }); - beforeAll(async () => { - // Create sender and receiver Safe - const sender = await deploySafeAndToken(core, accounts[0]); - const receiver = await deploySafeAndToken(core, accounts[1]); - // Create a trust connection between receiver and sender - await addTrustConnection(core, accounts[1], { - user: sender.safeAddress, - canSendTo: receiver.safeAddress, - limitPercentage: 50, - }); + // Send some Circles on that path and store payment note + const value = new web3.utils.BN(core.utils.toFreckles(3)); + paymentNote = 'Thank you for the fish'; + txHash = await core.token.transfer(accounts[0], { + from: sender.safeAddress, + to: receiver.safeAddress, + value, + paymentNote, + }); - // Send some Circles on that path and store payment note - const value = new web3.utils.BN(core.utils.toFreckles(3)); - paymentNote = 'Thank you for the fish'; - txHash = await core.token.transfer(accounts[0], { - from: sender.safeAddress, - to: receiver.safeAddress, - value, - paymentNote, + expect(web3.utils.isHexStrict(txHash)).toBe(true); }); - expect(web3.utils.isHexStrict(txHash)).toBe(true); - }); + it('should receive the payment note', async () => { + const result = await core.token.getPaymentNote(accounts[0], { + transactionHash: txHash, + }); - it('should receive the payment note', async () => { - const result = await core.token.getPaymentNote(accounts[0], { - transactionHash: txHash, + expect(result).toBe(paymentNote); }); - expect(result).toBe(paymentNote); - }); + it('should disallow access for other users and return null', async () => { + const result = await core.token.getPaymentNote(accounts[3], { + transactionHash: txHash, + }); - it('should disallow access for other users and return null', async () => { - const result = await core.token.getPaymentNote(accounts[3], { - transactionHash: txHash, + expect(result).toBe(null); }); - - expect(result).toBe(null); }); - }); - describe('Find transitive transfer steps', () => { - // it('should return max flow and possible path when using pathfinder binary.', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // }); - // expect(result.transferSteps.length).toBe(2); - // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - // }); - // it('should return max flow and possible path when using hops parameter in binary pathfinder', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // hops: 2, - // }); - // expect(result.transferSteps.length).toBe(2); - // expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - // expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - // expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[0].tokenOwnerAddress).toBe(safeAddresses[0]); - // expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - // expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - // expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - // expect(result.transferSteps[1].tokenOwnerAddress).toBe(safeAddresses[3]); - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - // }); - // it('should return 0 max flow and no path when using too low hops parameter in binary pathfinder', async () => { - // const value = new web3.utils.BN(core.utils.toFreckles(1)); - // const result = await core.token.requestTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value, - // hops: 1, - // }); - // expect(result.transferSteps.length).toBe(0); - - // // The `pathfinder` stops searching for max flow as soon as it found a - // // successful solution, therefore it returns a lower max flow than it - // // actually is (25). - // expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); - // }); - it('should return max flow and possible path when using pathfinder server.', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, + describe('Find transitive transfer steps', () => { + it(`should return max flow and possible path when using ${testPathfinderName} pathfinder.`, async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + }); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0][tokenOwnerAddressProperty]).toBe( + safeAddresses[0], + ); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1][tokenOwnerAddressProperty]).toBe( + safeAddresses[3], + ); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - }); - it('should return max flow and possible path when using max_transfers parameter in pathfinder server', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - maxTransfers: 2, + it(`should return max flow and possible path when using ${transferStepsProperty} parameter in ${testPathfinderName} pathfinder`, async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + [transferStepsProperty]: 2, + }); + expect(result.transferSteps.length).toBe(2); + expect(result.transferSteps[0].from).toBe(safeAddresses[0]); + expect(result.transferSteps[0].to).toBe(safeAddresses[3]); + expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[0][tokenOwnerAddressProperty]).toBe( + safeAddresses[0], + ); + expect(result.transferSteps[1].from).toBe(safeAddresses[3]); + expect(result.transferSteps[1].to).toBe(safeAddresses[4]); + expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); + expect(result.transferSteps[1][tokenOwnerAddressProperty]).toBe( + safeAddresses[3], + ); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); }); - expect(result.transferSteps.length).toBe(2); - expect(result.transferSteps[0].from).toBe(safeAddresses[0]); - expect(result.transferSteps[0].to).toBe(safeAddresses[3]); - expect(result.transferSteps[0].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[0].token_owner).toBe(safeAddresses[0]); - expect(result.transferSteps[1].from).toBe(safeAddresses[3]); - expect(result.transferSteps[1].to).toBe(safeAddresses[4]); - expect(result.transferSteps[1].value).toBe(core.utils.toFreckles(1)); - expect(result.transferSteps[1].token_owner).toBe(safeAddresses[3]); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(1)); - }); - it('should return 0 max flow and no path when using too low max_transfer parameter in pathfinder server', async () => { - const value = new web3.utils.BN(core.utils.toFreckles(1)); - const result = await core.token.requestTransferSteps(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value, - maxTransfers: 1, + it(`should return 0 max flow and no path when using too low ${transferStepsProperty} parameter in ${testPathfinderName} pathfinder`, async () => { + const value = new web3.utils.BN(core.utils.toFreckles(1)); + const result = await core.token.requestTransferSteps(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value, + [transferStepsProperty]: 1, + }); + expect(result.transferSteps.length).toBe(0); + // The `pathfinder` stops searching for max flow as soon as it found a + // successful solution, therefore it returns a lower max flow than it + // actually is (25). + expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); }); - expect(result.transferSteps.length).toBe(0); - // The `pathfinder` stops searching for max flow as soon as it found a - // successful solution, therefore it returns a lower max flow than it - // actually is (25). - expect(result.maxFlowValue).toBe(core.utils.toFreckles(0)); }); - }); - describe('Transitive Transactions', () => { - it('should get the current balance', async () => { - const balance = await core.token.getBalance(accounts[5], { - safeAddress: safeAddresses[5], + describe('Transitive Transactions', () => { + it('should get the current balance', async () => { + const balance = await core.token.getBalance(accounts[5], { + safeAddress: safeAddresses[5], + }); + + // It should be equals the initial UBI payout (called signupBonus) which was set during Hub + // contract deployment: + expect(balance).toMatchObject(new web3.utils.BN(signupBonus)); }); - // It should be equals the initial UBI payout (called signupBonus) which was set during Hub - // contract deployment: - expect(balance).toMatchObject(new web3.utils.BN(signupBonus)); - }); + it('should send Circles to someone directly', async () => { + const value = web3.utils.toBN(core.utils.toFreckles(5)); - it('should send Circles to someone directly', async () => { - const value = web3.utils.toBN(core.utils.toFreckles(5)); + // Unidirectional trust relationship from 1 to 2 + const indexFrom = 1; + const indexTo = 2; - // Unidirectional trust relationship from 1 to 2 - const indexFrom = 1; - const indexTo = 2; + // Transfer from 1 to 2 + const response = await core.token.transfer(accounts[indexFrom], { + from: safeAddresses[indexFrom], + to: safeAddresses[indexTo], + value, + }); - // Transfer from 1 to 2 - const response = await core.token.transfer(accounts[indexFrom], { - from: safeAddresses[indexFrom], - to: safeAddresses[indexTo], - value, + expect(web3.utils.isHexStrict(response)).toBe(true); }); - expect(web3.utils.isHexStrict(response)).toBe(true); - }); + it('should send Circles to someone transitively', async () => { + const sentCircles = 5; + const value = web3.utils.toBN(core.utils.toFreckles(sentCircles)); + const indexFrom = 0; + const indexTo = 4; - it('should send Circles to someone transitively', async () => { - const sentCircles = 5; - const value = web3.utils.toBN(core.utils.toFreckles(sentCircles)); - const indexFrom = 0; - const indexTo = 4; + const response = await core.token.transfer(accounts[indexFrom], { + from: safeAddresses[indexFrom], + to: safeAddresses[indexTo], + value, + }); - const response = await core.token.transfer(accounts[indexFrom], { - from: safeAddresses[indexFrom], - to: safeAddresses[indexTo], - value, + expect(web3.utils.isHexStrict(response)).toBe(true); + + const accountBalance = await loop( + 'Wait for balance to be lower after user transferred Circles', + () => { + return core.token.getBalance(accounts[indexFrom], { + safeAddress: safeAddresses[indexFrom], + }); + }, + (balance) => { + return ( + (core.utils.fromFreckles(balance) + 1).toString() === + (core.utils.fromFreckles(signupBonus) - sentCircles).toString() + ); + }, + ); + + const otherAccountBalance = await core.token.getBalance( + accounts[indexTo], + { + safeAddress: safeAddresses[indexTo], + }, + ); + + expect( + (core.utils.fromFreckles(otherAccountBalance) + 1).toString(), + ).toBe((core.utils.fromFreckles(signupBonus) + sentCircles).toString()); + expect((core.utils.fromFreckles(accountBalance) + 1).toString()).toBe( + (core.utils.fromFreckles(signupBonus) - sentCircles).toString(), + ); }); - expect(web3.utils.isHexStrict(response)).toBe(true); - - const accountBalance = await loop( - 'Wait for balance to be lower after user transferred Circles', - () => { - return core.token.getBalance(accounts[indexFrom], { - safeAddress: safeAddresses[indexFrom], - }); - }, - (balance) => { - return ( - (core.utils.fromFreckles(balance) + 1).toString() === - (core.utils.fromFreckles(signupBonus) - sentCircles).toString() - ); - }, - ); - - const otherAccountBalance = await core.token.getBalance( - accounts[indexTo], - { - safeAddress: safeAddresses[indexTo], - }, - ); - - expect( - (core.utils.fromFreckles(otherAccountBalance) + 1).toString(), - ).toBe((core.utils.fromFreckles(signupBonus) + sentCircles).toString()); - expect((core.utils.fromFreckles(accountBalance) + 1).toString()).toBe( - (core.utils.fromFreckles(signupBonus) - sentCircles).toString(), - ); - }); - - it('should fail sending Circles when maxflow is lower than requested transfer value', async () => { - await expect( - core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles('100')), - }), - ).rejects.toThrow(); - }); + it('should fail sending Circles when maxflow is lower than requested transfer value', async () => { + await expect( + core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles('100')), + }), + ).rejects.toThrow(); + }); - it('should fail sending Circles when there is no trust path between sender and receiver', async () => { - // Trust connection does not exist between node 0 and 5 - await expect( - core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[5], - value: web3.utils.toBN('1'), - }), - ).rejects.toThrow(); - }); + it('should fail sending Circles when there is no trust path between sender and receiver', async () => { + // Trust connection does not exist between node 0 and 5 + await expect( + core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[5], + value: web3.utils.toBN('1'), + }), + ).rejects.toThrow(); + }); - it('should fail to send Circles to someone transitively if maxTransfers value is too small to find a path', async () => { - await expect( - core.token.transfer(accounts[0], { - from: safeAddresses[0], - to: safeAddresses[4], - value: web3.utils.toBN(core.utils.toFreckles(5)), - maxTransfers: 1, - }), - ).rejects.toThrow(); - }); + it(`should fail to send Circles to someone transitively if ${transferStepsProperty} value is too small to find a path`, async () => { + await expect( + core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(5)), + [transferStepsProperty]: 1, + }), + ).rejects.toThrow(); + }); - // it('should fail sending Circles when data error when using the pathfinder binary', async () => { - // // Update the edges.csv file simulating data error: - // // Direct path does not exist between safeAddress 0 and 4, - // // thus we create a false edge between safeAddress 0 and 4 - // await Promise.resolve().then(() => { - // let edgesCSVdata = `${safeAddresses[0]},${safeAddresses[4]},${safeAddresses[0]},100000000000000000000`; - // execSync( - // `docker exec circles-api bash -c "echo '${edgesCSVdata}' >> edges-data/edges.csv" `, - // ); - // }); - // const valueToSend = '5'; - - // // Then we perform the transfer expecting it to fail: - // // Attempt to send an ammount which we know is higher - // // than the allowed by the blockchain data - // await expect( - // core.token.transfer(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - // }), - // ).rejects.toThrow(); - - // const updateResult = await core.token.updateTransferSteps(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - // }); - // await wait(3000); - // expect(updateResult.updated).toBe(true); - - // // Only after updating the path, the transfer can succeed - // const response = await core.token.transfer(accounts[0], { - // from: safeAddresses[0], - // to: safeAddresses[4], - // value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), - // }); - // expect(web3.utils.isHexStrict(response)).toBe(true); - // }); - - describe('requestUBIPayout', () => { - let token; - let payout; + if (!isPathfinderServer) { + it('should fail sending Circles when data error when using the pathfinder binary', async () => { + // Update the edges.csv file simulating data error: + // Direct path does not exist between safeAddress 0 and 4, + // thus we create a false edge between safeAddress 0 and 4 + await Promise.resolve().then(() => { + let edgesCSVdata = `${safeAddresses[0]},${safeAddresses[4]},${safeAddresses[0]},100000000000000000000`; + execSync( + `docker exec circles-api bash -c "echo '${edgesCSVdata}' >> edges-data/edges.csv" `, + ); + }); + const valueToSend = '5'; + + // Then we perform the transfer expecting it to fail: + // Attempt to send an ammount which we know is higher + // than the allowed by the blockchain data + await expect( + core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + }), + ).rejects.toThrow(); + + const updateResult = await core.token.updateTransferSteps( + accounts[0], + { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + }, + ); + await wait(3000); + expect(updateResult.updated).toBe(true); + + // Only after updating the path, the transfer can succeed + const response = await core.token.transfer(accounts[0], { + from: safeAddresses[0], + to: safeAddresses[4], + value: web3.utils.toBN(core.utils.toFreckles(valueToSend)), + }); + expect(web3.utils.isHexStrict(response)).toBe(true); + }); + } - beforeAll(async () => { - token = await getTokenContract(web3, tokenAddresses[5]); + describe('requestUBIPayout', () => { + let token; + let payout; - payout = await core.token.checkUBIPayout(accounts[5], { - safeAddress: safeAddresses[5], + beforeAll(async () => { + token = await getTokenContract(web3, tokenAddresses[5]); + payout = await core.token.checkUBIPayout(accounts[5], { + safeAddress: safeAddresses[5], + }); }); - }); - it('should add the next payout to our balance', async () => { - const balanceBefore = await token.methods - .balanceOf(safeAddresses[5]) - .call(); + it('should add the next payout to our balance', async () => { + const balanceBefore = await token.methods + .balanceOf(safeAddresses[5]) + .call(); - await core.token.requestUBIPayout(accounts[5], { - safeAddress: safeAddresses[5], - }); + await core.token.requestUBIPayout(accounts[5], { + safeAddress: safeAddresses[5], + }); - const balanceAfter = await token.methods - .balanceOf(safeAddresses[5]) - .call(); + const balanceAfter = await token.methods + .balanceOf(safeAddresses[5]) + .call(); - const expectedBalance = web3.utils - .toBN(balanceBefore) - .add(payout) - .toString(); + const expectedBalance = web3.utils + .toBN(balanceBefore) + .add(payout) + .toString(); - // Do not check for the exact amount as payout is changing every second - expect(web3.utils.toBN(balanceAfter).gt(expectedBalance)).toBe(true); + // Do not check for the exact amount as payout is changing every second + expect(web3.utils.toBN(balanceAfter).gt(expectedBalance)).toBe(true); + }); }); }); }); -}); +}; + +// Execute tests with server pathfinder +executeTests(createCore()); +// Execute tests with cli pathfinder +// executeTests(createCore({ pathfinderType: 'cli' })); From 410c769d81069799a8d1d736b3dcfd24f5c7f91e Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Mon, 20 Mar 2023 11:57:45 +0100 Subject: [PATCH 40/45] Add loops for Safe tests --- test/safe.test.js | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/test/safe.test.js b/test/safe.test.js index fe4b9c16..a1292e99 100644 --- a/test/safe.test.js +++ b/test/safe.test.js @@ -162,13 +162,7 @@ describe('Safe', () => { ); // Deploy Token - await core.token.deploy(accounts[0], { - safeAddress, - }); - - const tokenAddress = await core.token.getAddress(accounts[0], { - safeAddress, - }); + const tokenAddress = await deployToken(core, accounts[0], { safeAddress }); const code = await web3.eth.getCode(tokenAddress); expect(code).not.toBe('0x'); @@ -201,9 +195,15 @@ describe('Safe', () => { expect(web3.utils.isHexStrict(response)).toBe(true); - const owners = await core.safe.getOwners(accounts[0], { - safeAddress, - }); + const owners = await loop( + 'Wait for newly added address to show up as Safe owner', + () => { + return core.safe.getOwners(accounts[0], { + safeAddress, + }); + }, + (owners) => owners.length === 2, + ); expect(owners[0]).toBe(accounts[1].address); expect(owners[1]).toBe(accounts[0].address); @@ -228,9 +228,15 @@ describe('Safe', () => { expect(web3.utils.isHexStrict(response)).toBe(true); - const owners = await core.safe.getOwners(accounts[0], { - safeAddress, - }); + const owners = await loop( + 'Wait for newly added address to show up as Safe owner', + () => { + return core.safe.getOwners(accounts[0], { + safeAddress, + }); + }, + (owners) => owners.length === 1, + ); expect(owners[0]).toBe(accounts[0].address); expect(owners.length).toBe(1); @@ -332,9 +338,15 @@ describe('Safe', () => { expect(web3.utils.isHexStrict(response)).toBe(true); - const owners = await core.safe.getOwners(accounts[0], { - safeAddress: CRCVersionSafeAddress, - }); + const owners = await loop( + 'Wait for newly added address to show up as Safe owner', + () => { + return core.safe.getOwners(accounts[0], { + safeAddress: CRCVersionSafeAddress, + }); + }, + (owners) => owners.length === 2, + ); expect(owners[0]).toBe(accounts[1].address); expect(owners[1]).toBe(ownerCRCVersion.address); From 9b406f0a9fb235863a529e1d9d73dfe5df496c08 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Mon, 20 Mar 2023 12:31:50 +0100 Subject: [PATCH 41/45] Add loops for Organization tests --- test/organization.test.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/organization.test.js b/test/organization.test.js index c4827bf5..4aa946b7 100644 --- a/test/organization.test.js +++ b/test/organization.test.js @@ -69,9 +69,15 @@ describe('Organization', () => { expect(web3.utils.isHexStrict(txHash)).toBe(true); // isOrganization should be true now - isOrganization = await core.organization.isOrganization(account, { - safeAddress, - }); + isOrganization = await loop( + 'Wait for newly added address to show up as Safe owner', + () => { + return core.organization.isOrganization(account, { + safeAddress, + }); + }, + (isOrg) => isOrg, + ); expect(isOrganization).toBe(true); }); From cc9f3f497b917c8c03c34ee113fdfea36a61dc96 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Mon, 20 Mar 2023 13:02:12 +0100 Subject: [PATCH 42/45] Make lint happy --- test/safe.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/safe.test.js b/test/safe.test.js index a1292e99..9e6578cc 100644 --- a/test/safe.test.js +++ b/test/safe.test.js @@ -162,7 +162,9 @@ describe('Safe', () => { ); // Deploy Token - const tokenAddress = await deployToken(core, accounts[0], { safeAddress }); + const tokenAddress = await deployToken(core, accounts[0], { + safeAddress, + }); const code = await web3.eth.getCode(tokenAddress); expect(code).not.toBe('0x'); From daad4a82af059354eddd2acb4e8d8b1c44ed8c8d Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Mon, 20 Mar 2023 15:15:26 +0100 Subject: [PATCH 43/45] Remove unused code from test workflow --- .github/workflows/tests.yml | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1b4527f5..32bc90ce 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,11 +63,6 @@ jobs: - name: Download and migrate contracts working-directory: circles-docker run: ./scripts/migrate-contracts.sh - - - # - name: Update .env file - # working-directory: circles-docker - # run: ./scripts/update_contract_addresses.sh - name: Create and deploy subgraph working-directory: circles-docker @@ -79,15 +74,7 @@ jobs: - name: Container setup via docker-compose for pathfinder working-directory: circles-docker - run: docker compose -f docker-compose.pathfinder-pull.yml -p circles up --detach --build - - # - name: Run indexer-db background - # working-directory: circles-docker - # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml up -d indexer-db - - # - name: Run indexer-db-init - # working-directory: circles-docker - # run: docker compose -p circles -f docker-compose.pathfinder-pull.yml run --rm indexer-db-init + run: docker compose -f docker-compose.pathfinder-pull.yml -p circles up --detach --build - name: Install dependencies working-directory: circles-core From bbba905900c741eb59a23cc8e5e517756d290343 Mon Sep 17 00:00:00 2001 From: llunaCreixent Date: Mon, 20 Mar 2023 15:35:21 +0100 Subject: [PATCH 44/45] Add checking loop in updateToLastVersion method --- src/safe.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/safe.js b/src/safe.js index be656e04..3e1d40f0 100644 --- a/src/safe.js +++ b/src/safe.js @@ -10,6 +10,7 @@ import { getSafeContract, getSafeCRCVersionContract, } from '~/common/getContracts'; +import loop from '~/common/loop'; /** * Helper method to receive a list of all Gnosis Safe owners. @@ -546,6 +547,17 @@ export default function createSafeModule( `Safe with version ${safeVersion} failed to change the Master Copy`, ); } + + // Wait to check that the version is updated + await loop( + () => { + return getVersion(web3, options.safeAddress); + }, + (version) => { + return version == SAFE_LAST_VERSION; + }, + ); + // Then we setup the fallbackHandler const fallbackHandlerTxData = safeInstance.methods .setFallbackHandler(fallbackHandlerAddress) From 0208539dfe36b6d5fd4c7fb40047003f14a68987 Mon Sep 17 00:00:00 2001 From: Elena San Miguel Date: Mon, 20 Mar 2023 16:56:33 +0100 Subject: [PATCH 45/45] Use main branch of dockers for tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 32bc90ce..e648dac1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -49,7 +49,7 @@ jobs: uses: actions/checkout@v3 with: repository: CirclesUBI/circles-docker.git - ref: pathfinder2-dev-env + ref: main path: circles-docker - name: Setup docker repo