Kerwin下週四受邀於 #商業思維學院 授課。你可能常聽我分享K哥營運大中華區市場,出差歐美,定居雪梨的故事。但很難得,他終於開課了——把海外市場開拓「使業績5倍增長,營收破億」的實戰,理出可操作的步驟,教戰給同學😃。K哥剛在學院社團和同學們自我介紹,我也轉過來和大家分享😎
「我現於雪梨工作;身處規模8000人美國上市公司Atlassian,我們打造全球第一的敏捷工具 Jira/ Trello;《財星》500大企業 超過 80% 是我們客戶(包括SpaceX、NASA),公司股價超越 Facebook、微軟、Salesforce。
而我之所以能36歲,在全球頂尖企業擔任大中華區負責人,與我拓展海外市場,有絕對關係。
畢業幾年後,我發現自己在職場遇到晉升瓶頸,大公司給新人的機會太少,我很希望突破自己的格局。我給自己一個挑戰,去海外發展。
因為美國、中國是當今科技強國,當你打破國界限制,能做中國市場,又能與西方人共事;這將槓桿你的職涯,進入嶄新機遇——而熟稔中文、歡迎西方文化,正是台灣人的優勢。
在台灣公司工作,待在一間有前景與企圖心的企業,進軍國際市場的機會,早晚會出現在你眼前。我常在想,如果我能更早預備自己的海外拓展力,當時一定會掌握更多好機會。(我31歲才真正第一次出去「見世面」)
另一方面,不少人想去海外工作,但到了海外,除了技術職缺,難以發揮優勢。很多人以為只要出國就好了,但真正重點是,你到海外能夠「活得好」。如果你了解如何拓展海外市場,為公司帶來獲利,你不只不缺工作機會,你對公司絕對是重要角色。
其實,我當初只是誤打誤撞走入商業開發。作為沒有資源、沒有人脈的創業公司負責人,為了活下去,必須嘗試各種辦法,最終透過3人小團隊,使Jira從沒沒無聞,廣傳一~五線城市,業績翻5倍成長,達2500萬人民幣營收。也是這些經歷,讓我直接被hire到雪梨總部。
在全球Top科技公司爬升重要管理位置,你獲得的,絕對是最領先的國際視野&科技管理先趨。
我以前根本沒有想過,這是可能的事情。
話說回來,「海外拓展力」是一個能讓你「在世界到處走」的能力,但台灣很少有親上戰場的人,將海外市場拓展,系統化地教學傳授。我很希望將這條可行的路,傳承給台灣同學。
不要像我以前一樣覺得「不可能」,不要錯失讓自己站上國際舞台的機會。
在這一堂課,我會為同學預備:
1. 實戰經驗傳授
2. 你需要具備的思路&策略
3. 可實際執行的步驟
你將具備以下能力:
一、(從0~1) 到了一個全新海外市場,我沒有任何人脈、資源,我該從哪裡開始?
二、(從1~100) 當我有了一些資源,下一步該怎麼擴大影響力?(我會與你分享,我如何做到第一年賺進 500 萬人民幣,第二年 5 倍成長。歸納你可以實際執行的方式)
三、面對不同文化,我如何在海外市場有效擴散聲量(從無到有地建立專家形象&經營toB社群)。
那就期待下週四和同學課堂見!」
報名課程&了解課綱:https://learn.bizthinking.com.tw/packages/18Aaf1/intro
課程結束後,有30分鐘時間,你可以親自與K哥交流提問,我自己也很期待聽見同學的feedback。如果大家喜歡這樣的課程,不吝讓我們知道,K哥以後會更多分享自己的經驗。非常開心幫助同學邁向國際職場,一起共勉之!😊
邏輯實作1次 在 周逸自然團隊 Facebook 的精選貼文
默默的
我們的特色課
科學議題論壇(Science Issue Discussion)
已經累積 超過50個議題的里程碑了
中間還辦了1次 #實作營隊(3D列印營)
讓學生把上課學到的東西具象化出來
#特殊企劃1次:真假新聞判讀
#邏輯實作1次:沒有說明書的模型拼製(仿生獸企劃)
#大型成發1次:模擬TED講演(未來將邀請網紅、相關領域教授擔任評審)
#podcast實作1次:聲音的藝術
當然還有數不盡的活動,像是 #貢丸湯模擬艾克曼螺旋、#人造肉的試吃...
一路走來真的很辛苦
甚至像要放棄,還遇到疫情
但真的謝謝一直以來支持我們的家長、主任們
#我們即將往100個議題邁進!
#還有許多神祕的企劃
請密切關注我們的粉專
除了既有的服務據點外
竹北市「哲人數理培訓中心」
新竹市「山熊科學實驗教室」
我們準備將我們的課程 #免費放到線上作推廣
每月開放一些科學時事議題
另外要準備開放 #會員制
每人單獨的學習資料庫
(將作品電子化、歸檔未來可使用的個人作品集)
成立線上讀書會
符合我們科學議題"論壇"的精神
敬請期待
邏輯實作1次 在 Taipei Ethereum Meetup Facebook 的最佳解答
📜 [專欄新文章] 可升級合約介紹 - 鑽石合約(EIP-2535 Diamond standard)
✍️ Kimi Wu
📥 歡迎投稿: https://medium.com/taipei-ethereum-meetup #徵技術分享文 #使用心得 #教學文 #medium
Photo by Evie S. on Unsplash
前言
可升級合約簡單來說是透過 proxy contract(代理合約)來達成,藉由代理合約去呼叫欲執行的合約,若要升級,則把代理合約中的指向的地址換為新的合約地址即可。而執行的方式則是透過 delegateCall,但 delegateCall 不會更動目標合約的狀態。所以要怎麼處理變數,就是一門學問了。
舉例來說,contract B 有個變數 uint256 x,初始值為 0, 而 function setX(uint256),可以改變 x 的值。proxy contract A 使用 delegatecall 呼叫 contract B 的 setX(10),交易結束後,contract B中的 x 依然還是 0。
OpenZeppelin 提出了三種實作方式,可以做到可升級合約,細節可參考 Proxy Patterns,而最終的實作選用了 Unstructured Storage的這個方式,這種方式對於開發較友善,開發時不需特別處理 state variables(不過升級時就需要特別注意了)。而這篇主要是介紹 Diamond standard,OpenZeppelin 的可升級合約就不多做介紹。
USDC V2 : Upgrading a multi-billion dollar ERC-20 token 詳細地介紹代理合約跟變數儲存之間的關係,不了解升級合約的原理,建議先看看。
鑽石合約
名詞介紹
diamond:合約本體,是一個代理合約,無商業邏輯
facet:延伸的合約(實際商業邏輯實作的合約)
loupe:也是一個 facet,負責查詢的功能。可查詢此 diamond所提供的 facet與facet所提供的函式
diamondCut:一組函式,用來管理(增加/取代/減少)此 diamond合約所支援的功能
Loupe
直接來看 loupe的介面,從宣告就能很清楚暸解 diamond合約的實作方式,loupe宣告了一個結構 Facet,Facet結構包含一個地址及 function selector 陣列,所以我們只需要記錄一個 Facet陣列就可以得知這個 diamond 合約有多少個延伸合約及所支援的功能(loupe只定義結構,而實際變數是存在diamon合約中的)。也就是 diamond合約中只記錄延伸合約的地址及其支援的 function selectors,及少數 diamond合約的管理邏輯,並無商業邏輯,因此可以外掛非常非常多的合約上去(就像一個Hub),也就可以突破一個合約只有24K的限制。
// A loupe is a small magnifying glass used to look at diamonds.interface IDiamondLoupe { struct Facet { address facetAddress; bytes4[] functionSelectors; } function facets() external view returns (Facet[] memory facets_); function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_); function facetAddresses() external view returns (address[] memory facetAddresses_); function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_);}
DiamondCut
至於 facet在 diamond合約上的註冊或是修改,就由 diamondCut負責,從以下程式碼可以清楚瞭解其功能(EIP中有規範,每次改變都需要發送DiamondCut事件)
interface IDiamondCut { enum FacetCutAction {Add, Replace, Remove} // Add=0, Replace=1, Remove=2 struct FacetCut { address facetAddress; FacetCutAction action; bytes4[] functionSelectors; } function diamondCut( FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external; event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);}
Diamond合約
接下來就是最核心的部分 — diamond本體合約。以下是官方的範例,方法上跟 OpenZeppelin 一樣使用 fallback 函式跟 delegateCall 。
呼叫合約所不支援的函式,就會去執行 fallback 函式,fallback 函式中再透過 delegateCall 呼叫 facet 合約相對應的函式
fallback() external payable { address facet = selectorTofacet[msg.sig]; require(facet != address(0)); // Execute external function from facet using delegatecall and return any value. assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 {revert(0, returndatasize())} default {return (0, returndatasize())} }}
主要的差異在於變數的處理,OpenZepplin 是針對單一合約設計的代理合約(也就是每個合約都有自己的代理合約),所以無法處理單一代理合約儲存多個合約的變數(state variables)的狀況(後有圖例)。先由官方的範例程式來了解是怎麼處理變數的
在官方的範例中,都是以更改合約 owner 為例子
首先看到 DimaondStorage這個結構,結構中的前面三個變數都是在維持 diamond合約的運作(同上面loupe的範例),最後一個變數 contractOwner就是我們商業邏輯中所需的變數。
接著看到 function diamondStorage(),取變數的方式就跟OpenZeppelin 儲存特定變數方式一樣(EIP-1967),是把變數存到一個遠方不會跟其他變數碰撞到的位置,在這裡就是從 DIMOND_STORAGE_POSITION 這個 storage slot 讀取。
在實作上就可以有 LibDiamond1 ,宣告DIMOND_STORAGE_POSITION1=keccak256("diamond.standard.diamond.storage1") ,負責處理另一組的變數。藉由這種方式讓每個 facet合約有屬於自己合約的變數, facet合約間就不會互相影響。而最下方的 setContractOwner 是實際使用的範例。
library LibDiamond {
bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
struct FacetAddressAndSelectorPosition { address facetAddress; uint16 selectorPosition; }
struct DiamondStorage { mapping(bytes4 => FacetAddressAndSelectorPosition) facetAddressAndSelectorPosition; bytes4[] selectors; mapping(bytes4 => bool) supportedInterfaces; // owner of the contract address contractOwner; }
function diamondStorage() internal pure returns (DiamondStorage storage ds) { bytes32 position = DIAMOND_STORAGE_POSITION; assembly { ds.slot := position } }
function setContractOwner(address _newOwner) internal { DiamondStorage storage ds = diamondStorage(); address previousOwner = ds.contractOwner; ds.contractOwner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); }
每個 library 處理了一組或多組變數的存取, facet 合約透過 library 對變數做操作。也就是把變數存在diamond主體合約,延伸的 facet合約只處理邏輯,是透過 library 去操作變數。
下面圖中清楚地解釋了 facet合約,function selectors 與變數之間的關係,從最左上這邊有個 facets 的 map,紀錄了哪個 selector 在哪個合約中,例如func1, func2是 FacetA的函式。左下角宣告了變數,每組變數的存取如同上述 library 的方式處理。
https://eips.ethereum.org/EIPS/eip-2535#diagrams
在 diamond的設計中,每個 facet合約都是獨立的,因此可以重複使用(跟library 的概念一樣)
https://eips.ethereum.org/EIPS/eip-2535#diagrams
小結
diamond合約使用不同的設計來達成合約的可升級性,藉由這種Hub方式可隨時擴充/移除功能,讓合約不再受限於24KB的限制,此外充分的模組化,讓每次升級的範圍可以很小。最後,因為跟library一樣只處理邏輯,並無狀態儲存,所以可以重複被不同的diamond合約所使用。
雖然又不少好處,也是有些缺點。首先,術語名詞太多,facet, diamondCut, loupe等等(其實還有好幾個,不過沒有介紹到那些部分,所以沒有寫出來)。開發上不直覺,把變數跟邏輯拆開,若要再加上合約之間的繼承關係,容易搞混,不易維護。最後,gas的花費,在函式的讀取、呼叫,變數的存取、傳遞都會有不少的額外支出。Trail of Bits 專欄中有點出更多的缺陷 Good idea, bad design: How the Diamond standard falls short,不過作者也有反擊 Addressing Josselin Feist’s Concern’s of EIP-2535 Diamond Standard,有興趣的讀者可以自行看看、比較。
為了模組化及彈性,diamond合約在設計上有點太複雜(over engineering),會造成可讀性越差(這點也是Vyper誕生的原因之一),而可讀性越差就越容易產生bug、也越不容易抓到bug,而在defi專案中,一個小小的bug通常代表著大筆金額的損失 😱😱😱。
雖然如此,筆者還是覺得很酷,有些設計的思維仍然可以使用在自己的專案
ref:
EIP 2535
Diamond 實作
Addressing Josselin Feist’s Concern’s of EIP-2535 Diamond Standard
OpenZeppelin upgradeable contract
可升級合約介紹 - 鑽石合約(EIP-2535 Diamond standard) was originally published in Taipei Ethereum Meetup on Medium, where people are continuing the conversation by highlighting and responding to this story.
👏 歡迎轉載分享鼓掌
邏輯實作1次 在 FPGA系統設計實務_蕭宇宏_循序邏輯電路實作(I) - YouTube 的推薦與評價
FPGA系統設計實務_蕭宇宏_循序 邏輯 電路 實作 (I)_循序 邏輯 電路概論 ... DeltaMOOCx 台達磨課師是大學及高中/高工的免費公益磨課師(MOOCs)平臺。練習題、討論 ... ... <看更多>